Back to index

lightning-sunbird  0.9+nobinonly
nsDogbertProfileMigrator.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is The Mail Profile Migrator.
00016  *
00017  * The Initial Developer of the Original Code is Scott MacGregor
00018  * Portions created by the Initial Developer are Copyright (C) 2004
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *  Scott MacGregor <mscott@mozilla.org>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // this file is mostly a copy of nsPrefMigration.cpp...old nsFileSpec warts and all
00039 
00040 #include "nsMailProfileMigratorUtils.h"
00041 #include "nsCRT.h"
00042 #include "nsDirectoryServiceDefs.h"
00043 #include "nsIObserverService.h"
00044 #include "nsIPasswordManagerInternal.h"
00045 #include "nsIPrefLocalizedString.h"
00046 #include "nsIPrefService.h"
00047 #include "nsIServiceManager.h"
00048 #include "nsISupportsArray.h"
00049 #include "nsISupportsPrimitives.h"
00050 #include "nsNetCID.h"
00051 #include "nsNetUtil.h"
00052 #include "nsDogbertProfileMigrator.h"
00053 #include "nsIRelativeFilePref.h"
00054 #include "nsAppDirectoryServiceDefs.h"
00055 #include "nsVoidArray.h"
00056 #include "prprf.h"
00057 #include "prmem.h"
00058 #include "prio.h"
00059 #include "prenv.h"
00060 #include "NSReg.h"
00061 
00062 // lots of includes required for the nsPrefMigration.cpp code that we copied:
00063 #include "nsICharsetConverterManager.h"
00064 #include "nsIPlatformCharset.h"
00065 #include "nsIPref.h"
00066 #include "nsIFileSpec.h"
00067 #include "nsFileSpec.h"
00068 #include "nsFileStream.h"
00069 
00070 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00071 static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
00072 static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
00073 
00074 #define MIGRATION_PROPERTIES_URL "chrome://messenger/locale/migration/migration.properties"
00075 
00076 #ifndef MAXPATHLEN
00077 #ifdef _MAX_PATH
00078 #define MAXPATHLEN _MAX_PATH
00079 #elif defined(CCHMAXPATH)
00080 #define MAXPATHLEN CCHMAXPATH
00081 #else
00082 #define MAXPATHLEN 1024
00083 #endif
00084 #endif
00085 
00086 #if (defined(XP_UNIX) || defined(XP_BEOS)) && !defined(XP_MACOSX)
00087 #define PREF_FILE_NAME_IN_4x      "preferences.js"
00088 #define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "mailrule"
00089 #define POP_MAIL_FILTER_FILE_NAME_IN_4x "mailrule"
00090 #define MAIL_SUMMARY_SUFFIX_IN_4x ".summary"
00091 #define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
00092 #define NEWSRC_PREFIX_IN_4x ".newsrc-"
00093 #define SNEWSRC_PREFIX_IN_4x ".snewsrc-"
00094 #define POPSTATE_FILE_IN_4x "popstate"
00095 #define PSM_CERT7_DB "cert7.db"
00096 #define PSM_KEY3_DB "key3.db"
00097 #define PSM_SECMODULE_DB "secmodule.db"
00098 #define HOME_ENVIRONMENT_VARIABLE         "HOME"
00099 #define PROFILE_HOME_ENVIRONMENT_VARIABLE "PROFILE_HOME"
00100 #define DEFAULT_UNIX_PROFILE_NAME         "default"
00101 #elif defined(XP_MAC) || defined(XP_MACOSX)
00102 #define OLDREG_NAME               "Netscape Registry"
00103 #define OLDREG_DIR                NS_MAC_PREFS_DIR
00104 #define PREF_FILE_NAME_IN_4x      "Netscape Preferences"
00105 #define MAC_RULES_FILE_ENDING_STRING_IN_4X " Rules"
00106 #define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "<hostname> Rules"
00107 #define POP_MAIL_FILTER_FILE_NAME_IN_4x "Filter Rules"
00108 #define MAIL_SUMMARY_SUFFIX_IN_4x ".snm"
00109 #define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
00110 #define POPSTATE_FILE_IN_4x "Pop State"
00111 #define SECURITY_PATH "Security"
00112 #define PSM_CERT7_DB "Certificates7"
00113 #define PSM_KEY3_DB "Key Database3"
00114 #define PSM_SECMODULE_DB "Security Modules"
00115 #else /* XP_WIN || XP_OS2 */
00116 #define PREF_FILE_NAME_IN_4x      "prefs.js"
00117 #define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "rules.dat"
00118 #define POP_MAIL_FILTER_FILE_NAME_IN_4x "rules.dat"
00119 #define MAIL_SUMMARY_SUFFIX_IN_4x ".snm"
00120 #define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
00121 #define OLDREG_NAME               "nsreg.dat"
00122 #ifdef XP_WIN
00123 #define OLDREG_DIR                NS_WIN_WINDOWS_DIR
00124 #else
00125 #define OLDREG_DIR                NS_OS2_DIR
00126 #endif
00127 // purposely not defined, since it was in the right place
00128 // and with the right name in 4.x
00129 //#define POPSTATE_FILE_IN_4x "popstate.dat"
00130 #define PSM_CERT7_DB "cert7.db"
00131 #define PSM_KEY3_DB "key3.db"
00132 #define PSM_SECMODULE_DB "secmod.db"
00133 #endif /* XP_UNIX */
00134 
00135 #define SUMMARY_SUFFIX_IN_5x ".msf"
00136 #define IMAP_MAIL_FILTER_FILE_NAME_IN_5x "rules.dat"
00137 #define POP_MAIL_FILTER_FILE_NAME_IN_5x "rules.dat"
00138 #define POPSTATE_FILE_IN_5x "popstate.dat"
00139 
00140 // only UNIX had movemail in 4.x
00141 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00142 #define HAVE_MOVEMAIL 1
00143 #endif /* XP_UNIX */
00144 
00145 #define PREMIGRATION_PREFIX "premigration."
00146 #define ADDRBOOK_FILE_EXTENSION_IN_4X  ".na2"
00147 #define PREF_FILE_HEADER_STRING "# Mozilla User Preferences    " 
00148 #define MAX_PREF_LEN 1024
00149 
00150 // this is for the hidden preference setting in mozilla/modules/libpref/src/init/mailnews.js
00151 // pref("mail.migration.copyMailFiles", true);
00152 //
00153 // see bugzilla bug 80035 (http://bugzilla.mozilla.org/show_bug.cgi?id=80035)
00154 //
00155 // the default value for this setting is true which means when migrating from
00156 // Netscape 4.x, mozilla will copy all the contents of Local Folders and Imap
00157 // Folder to the newly created subfolders of migrated mozilla profile
00158 // when this value is set to false, mozilla will not copy these contents and
00159 // still share them with Netscape 4.x
00160 //
00161 // Advantages of forbidding copy operation:
00162 //     reduce the disk usage
00163 //     quick migration
00164 // Disadvantage of forbidding copy operation:
00165 //     without perfect lock mechamism, there is possibility of data corruption
00166 //     when Netscape 4.x and mozilla run at the same time and access the same
00167 //     mail file at the same time
00168 #define PREF_MIGRATION_MODE_FOR_MAIL "mail.migration.copyMailFiles"
00169 #define PREF_MAIL_DIRECTORY "mail.directory"
00170 #define PREF_NEWS_DIRECTORY "news.directory"
00171 #define PREF_MAIL_IMAP_ROOT_DIR "mail.imap.root_dir"
00172 #define PREF_NETWORK_HOSTS_POP_SERVER "network.hosts.pop_server"
00173 #define PREF_4X_NETWORK_HOSTS_IMAP_SERVER "network.hosts.imap_servers"  
00174 #define PREF_MAIL_SERVER_TYPE      "mail.server_type"
00175 #define PREF_BROWSER_CACHE_DIRECTORY "browser.cache.directory"
00176 #define POP_4X_MAIL_TYPE 0
00177 #define IMAP_4X_MAIL_TYPE 1
00178 #ifdef HAVE_MOVEMAIL
00179 #define MOVEMAIL_4X_MAIL_TYPE 2
00180 #define NEW_MOVEMAIL_DIR_NAME "movemail"
00181 #endif /* HAVE_MOVEMAIL */
00182 
00183 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00184 /* a 4.x profile on UNIX is rooted at something like
00185  * "/u/sspitzer/.netscape"
00186  * profile + OLD_MAIL_DIR_NAME = "/u/sspitzer/.netscape/../nsmail" = "/u/sspitzer/nsmail"
00187  * profile + OLD_NEWS_DIR_NAME = "/u/sspitzer/.netscape/xover-cache"
00188  * profile + OLD_IMAPMAIL_DIR_NAME = "/u/sspitzer/.netscape/../ns_imap" = "/u/sspitzer/ns_imap"
00189  * which is as good as we're going to get for defaults on UNIX.
00190  */
00191 #define OLD_MAIL_DIR_NAME "/../nsmail"
00192 #define OLD_NEWS_DIR_NAME "/xover-cache"
00193 #define OLD_IMAPMAIL_DIR_NAME "/../ns_imap"
00194 #else
00195 #define OLD_MAIL_DIR_NAME "Mail"
00196 #define OLD_NEWS_DIR_NAME "News"
00197 #define OLD_IMAPMAIL_DIR_NAME "ImapMail"
00198 #endif /* XP_UNIX */
00199 
00200 #define NEW_MAIL_DIR_NAME "Mail"
00201 #define NEW_NEWS_DIR_NAME "News"
00202 #define NEW_IMAPMAIL_DIR_NAME "ImapMail"
00203 #define NEW_LOCAL_MAIL_DIR_NAME "Local Folders"
00204 
00205 #define NEW_DIR_SUFFIX "5"
00206 #define PREF_FILE_NAME_IN_5x "prefs.js"
00207 
00208 static PRBool nsCStringEndsWith(nsCString& name, const char *ending);
00209 
00210 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
00211 static PRBool nsCStringStartsWith(nsCString& name, const char *starting);
00212 #endif
00213 
00215 // nsDogbertProfileMigrator
00216 struct PrefBranchStruct {
00217   char*         prefName;
00218   PRInt32       type;
00219   union {
00220     char*       stringValue;
00221     PRInt32     intValue;
00222     PRBool      boolValue;
00223     PRUnichar*  wstringValue;
00224   };
00225 };
00226 
00227 NS_IMPL_ISUPPORTS2(nsDogbertProfileMigrator, nsIMailProfileMigrator, nsITimerCallback)
00228 
00229 
00230 nsDogbertProfileMigrator::nsDogbertProfileMigrator()
00231 {
00232   mObserverService = do_GetService("@mozilla.org/observer-service;1");
00233   mMaxProgress = LL_ZERO;
00234   mCurrentProgress = LL_ZERO;
00235 }
00236 
00237 nsDogbertProfileMigrator::~nsDogbertProfileMigrator()
00238 {           
00239 }
00240 
00242 // nsITimerCallback
00243 
00244 NS_IMETHODIMP
00245 nsDogbertProfileMigrator::Notify(nsITimer *timer)
00246 {
00247   CopyNextFolder();
00248   return NS_OK;
00249 }
00250 
00251 void nsDogbertProfileMigrator::CopyNextFolder() 
00252 {
00253   if (mFileCopyTransactionIndex < mFileCopyTransactions->Count())
00254   {
00255     PRUint32 percentage = 0;
00256     fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->SafeElementAt(mFileCopyTransactionIndex++);
00257     if (fileTransaction) // copy the file
00258     {
00259       fileTransaction->srcFile->CopyTo(fileTransaction->destFile, fileTransaction->newName);
00260 
00261       // add to our current progress
00262       PRInt64 fileSize;
00263       fileTransaction->srcFile->GetFileSize(&fileSize);
00264       LL_ADD(mCurrentProgress, mCurrentProgress, fileSize);
00265 
00266       PRInt64 percentDone;
00267       LL_MUL(percentDone, mCurrentProgress, 100);
00268 
00269       LL_DIV(percentDone, percentDone, mMaxProgress);
00270       
00271       LL_L2UI(percentage, percentDone);
00272 
00273       nsAutoString index;
00274       index.AppendInt( percentage ); 
00275 
00276       NOTIFY_OBSERVERS(MIGRATION_PROGRESS, index.get());
00277     }
00278     // fire a timer to handle the next one. 
00279     mFileIOTimer = do_CreateInstance("@mozilla.org/timer;1");
00280     if (mFileIOTimer)
00281       mFileIOTimer->InitWithCallback(NS_STATIC_CAST(nsITimerCallback *, this), percentage == 100 ? 500 : 0, nsITimer::TYPE_ONE_SHOT);
00282   } else
00283     EndCopyFolders();
00284   
00285   return;
00286 }
00287 
00288 void nsDogbertProfileMigrator::EndCopyFolders() 
00289 {
00290   // clear out the file transaction array
00291   if (mFileCopyTransactions)
00292   {
00293     PRUint32 count = mFileCopyTransactions->Count();
00294     for (PRUint32 i = 0; i < count; ++i) 
00295     {
00296       fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->ElementAt(i);
00297       if (fileTransaction)
00298       {
00299         fileTransaction->srcFile = nsnull;
00300         fileTransaction->destFile = nsnull;
00301         delete fileTransaction;
00302       }
00303     }
00304   
00305     mFileCopyTransactions->Clear();
00306     delete mFileCopyTransactions;
00307   }
00308 
00309   // notify the UI that we are done with the migration process
00310   nsAutoString index;
00311   index.AppendInt(nsIMailProfileMigrator::MAILDATA); 
00312   NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
00313 
00314   NOTIFY_OBSERVERS(MIGRATION_ENDED, nsnull);
00315 }
00316 
00318 // nsIMailProfileMigrator
00319 
00320 NS_IMETHODIMP
00321 nsDogbertProfileMigrator::Migrate(PRUint16 aItems, nsIProfileStartup* aStartup, const PRUnichar* aProfile)
00322 {
00323   nsresult rv = NS_OK;
00324   PRBool aReplace = aStartup ? PR_TRUE : PR_FALSE;
00325 
00326   if (!mTargetProfile) {
00327     GetProfilePath(aStartup, mTargetProfile);
00328     if (!mTargetProfile) return NS_ERROR_FAILURE;
00329   }
00330   if (!mSourceProfile)
00331     GetSourceProfile(aProfile);
00332 
00333   NOTIFY_OBSERVERS(MIGRATION_STARTED, nsnull);
00334 
00335   rv = CopyPreferences();
00336   return rv;
00337 }
00338 
00339 NS_IMETHODIMP
00340 nsDogbertProfileMigrator::GetMigrateData(const PRUnichar* aProfile, 
00341                                            PRBool aReplace, 
00342                                            PRUint16* aResult)
00343 {
00344   // add some extra migration fields for things we also migrate
00345   *aResult |= nsIMailProfileMigrator::ACCOUNT_SETTINGS 
00346            | nsIMailProfileMigrator::MAILDATA 
00347            | nsIMailProfileMigrator::NEWSDATA
00348            | nsIMailProfileMigrator::ADDRESSBOOK_DATA;
00349 
00350   return NS_OK;
00351 }
00352 
00353 NS_IMETHODIMP
00354 nsDogbertProfileMigrator::GetSourceExists(PRBool* aResult)
00355 {
00356   nsCOMPtr<nsISupportsArray> profiles;
00357   GetSourceProfiles(getter_AddRefs(profiles));
00358 
00359   if (profiles) { 
00360     PRUint32 count;
00361     profiles->Count(&count);
00362     *aResult = count > 0;
00363   }
00364   else
00365     *aResult = PR_FALSE;
00366 
00367   return NS_OK;
00368 }
00369 
00370 NS_IMETHODIMP
00371 nsDogbertProfileMigrator::GetSourceHasMultipleProfiles(PRBool* aResult)
00372 {
00373   nsCOMPtr<nsISupportsArray> profiles;
00374   GetSourceProfiles(getter_AddRefs(profiles));
00375 
00376   if (profiles) {
00377     PRUint32 count;
00378     profiles->Count(&count);
00379     *aResult = count > 1;
00380   }
00381   else
00382     *aResult = PR_FALSE;
00383 
00384   return NS_OK;
00385 }
00386 
00387 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_MACOSX)
00388 NS_IMETHODIMP
00389 nsDogbertProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
00390 {
00391   if (!mProfiles) {
00392     nsresult rv;
00393 
00394     rv = NS_NewISupportsArray(getter_AddRefs(mProfiles));
00395     NS_ENSURE_SUCCESS(rv, rv);
00396 
00397     nsCOMPtr<nsIFile> regFile;
00398     rv = NS_GetSpecialDirectory(OLDREG_DIR, getter_AddRefs(regFile));
00399     NS_ENSURE_SUCCESS(rv, rv);
00400     regFile->AppendNative(NS_LITERAL_CSTRING(OLDREG_NAME));
00401   
00402     nsCAutoString path;
00403     rv = regFile->GetNativePath(path);
00404     NS_ENSURE_SUCCESS(rv, rv);
00405 
00406     if (NR_StartupRegistry())
00407       return NS_ERROR_FAILURE;
00408 
00409     HREG reg = nsnull;
00410     REGENUM enumstate = 0;
00411 
00412     if (NR_RegOpen(path.get(), &reg)) {
00413       NR_ShutdownRegistry();
00414       return NS_ERROR_FAILURE;
00415     }
00416 
00417     char profileName[MAXREGNAMELEN];
00418     while (!NR_RegEnumSubkeys(reg, ROOTKEY_USERS, &enumstate,
00419                               profileName, MAXREGNAMELEN, REGENUM_CHILDREN)) {
00420       nsCOMPtr<nsISupportsString> nameString
00421         (do_CreateInstance("@mozilla.org/supports-string;1"));
00422       if (nameString) {
00423         nameString->SetData(NS_ConvertUTF8toUTF16(profileName));
00424         mProfiles->AppendElement(nameString);
00425       }
00426     }
00427   }
00428   
00429   NS_IF_ADDREF(*aResult = mProfiles);
00430   return NS_OK;
00431 }
00432 #else // XP_UNIX
00433 
00434 NS_IMETHODIMP
00435 nsDogbertProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
00436 {
00437   nsresult rv;
00438   const char* profileDir  = PR_GetEnv(PROFILE_HOME_ENVIRONMENT_VARIABLE);
00439 
00440   if (!profileDir) {
00441     profileDir = PR_GetEnv(HOME_ENVIRONMENT_VARIABLE);
00442   }
00443   if (!profileDir) return NS_ERROR_FAILURE;
00444 
00445   nsCAutoString profilePath(profileDir);
00446   profilePath += "/.netscape";
00447 
00448   nsCOMPtr<nsILocalFile> profileFile;
00449   rv = NS_NewNativeLocalFile(profilePath, PR_TRUE, getter_AddRefs(profileFile));
00450   NS_ENSURE_SUCCESS(rv, rv);
00451 
00452   nsCOMPtr<nsIFile> prefFile;
00453   rv = profileFile->Clone(getter_AddRefs(prefFile));
00454   NS_ENSURE_SUCCESS(rv, rv);
00455 
00456   prefFile->AppendNative(NS_LITERAL_CSTRING("preferences.js"));
00457 
00458   PRBool exists;
00459   rv = prefFile->Exists(&exists);
00460   if (NS_FAILED(rv) || !exists) {
00461     return NS_ERROR_FAILURE;
00462   }
00463 
00464   mSourceProfile = profileFile;
00465 
00466   rv = NS_NewISupportsArray(getter_AddRefs(mProfiles));
00467   NS_ENSURE_SUCCESS(rv, rv);
00468 
00469   nsCOMPtr<nsISupportsString> nameString
00470     (do_CreateInstance("@mozilla.org/supports-string;1"));
00471   if (!nameString) return NS_ERROR_FAILURE;
00472 
00473   nameString->SetData(NS_LITERAL_STRING("Netscape 4.x"));
00474   mProfiles->AppendElement(nameString);
00475   NS_ADDREF(*aResult = mProfiles);
00476   return NS_OK;
00477 }
00478 
00479 #endif // GetSourceProfiles
00480 
00481 // on win/mac/os2, NS4x uses a registry to determine profile locations
00482 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
00483 void nsDogbertProfileMigrator::GetSourceProfile(const PRUnichar* aProfile)
00484 {
00485   nsresult rv;
00486 
00487   nsCOMPtr<nsIFile> regFile;
00488   rv = NS_GetSpecialDirectory(OLDREG_DIR, getter_AddRefs(regFile));
00489   if (NS_FAILED(rv)) return;
00490 
00491   regFile->AppendNative(NS_LITERAL_CSTRING(OLDREG_NAME));
00492   
00493   nsCAutoString path;
00494   rv = regFile->GetNativePath(path);
00495   if (NS_FAILED(rv)) return;
00496 
00497   if (NR_StartupRegistry())
00498     return;
00499 
00500   HREG reg = nsnull;
00501   RKEY profile = nsnull;
00502 
00503   if (NR_RegOpen(path.get(), &reg))
00504     goto cleanup;
00505 
00506   {
00507     // on macos, registry entries are UTF8 encoded
00508     NS_ConvertUTF16toUTF8 profileName(aProfile);
00509 
00510     if (NR_RegGetKey(reg, ROOTKEY_USERS, profileName.get(), &profile))
00511       goto cleanup;
00512   }
00513 
00514   char profilePath[MAXPATHLEN];
00515   if (NR_RegGetEntryString(reg, profile, "ProfileLocation", profilePath, MAXPATHLEN))
00516     goto cleanup;
00517 
00518   mSourceProfile = do_CreateInstance("@mozilla.org/file/local;1");
00519   if (!mSourceProfile) goto cleanup;
00520 
00521   {
00522     // the string is UTF8 encoded, which forces us to do some strange string-do
00523     rv = mSourceProfile->InitWithPath(NS_ConvertUTF8toUTF16(profilePath));
00524   }
00525 
00526   if (NS_FAILED(rv))
00527     mSourceProfile = nsnull;
00528 
00529 cleanup:
00530   if (reg)
00531     NR_RegClose(reg);
00532   NR_ShutdownRegistry();
00533 }
00534 #else
00535 
00536 void
00537 nsDogbertProfileMigrator::GetSourceProfile(const PRUnichar* aProfile)
00538 {
00539   // if GetSourceProfiles didn't do its magic, we're screwed
00540 }
00541 
00542 #endif
00543 
00544 
00545 nsresult nsDogbertProfileMigrator::CopyPreferences()
00546 {
00547   // Load the source pref file
00548 
00549   mPrefs = do_GetService(kPrefServiceCID);
00550 
00551   nsCAutoString oldProfDirStr;
00552   nsCAutoString newProfDirStr;
00553 
00554   nsCOMPtr<nsILocalFile> sourceProfile = do_QueryInterface(mSourceProfile);
00555   nsCOMPtr<nsILocalFile> targetProfile = do_QueryInterface(mTargetProfile);
00556 
00557   sourceProfile->GetPersistentDescriptor(oldProfDirStr);
00558   targetProfile->GetPersistentDescriptor(newProfDirStr); 
00559 
00560   nsAutoString index;
00561   index.AppendInt(nsIMailProfileMigrator::MAILDATA); 
00562   NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
00563 
00564   ProcessPrefsCallback(oldProfDirStr.get(), newProfDirStr.get());
00565 
00566   // Generate the max progress value now that we know all of the files we need to copy
00567   PRUint32 count = mFileCopyTransactions->Count();
00568   for (PRUint32 i = 0; i < count; ++i) 
00569   {
00570     fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->ElementAt(i);
00571     if (fileTransaction)
00572     {
00573       PRInt64 fileSize; 
00574       fileTransaction->srcFile->GetFileSize(&fileSize);
00575       LL_ADD(mMaxProgress, mMaxProgress, fileSize);
00576     }
00577   }
00578 
00579   CopyNextFolder();
00580   return NS_OK;
00581 }
00582 
00583 /*--------------------------------------------------------------------------
00584  * ProcessPrefsCallback is the primary funtion for the class nsPrefMigration.
00585  *
00586  * Called by: The Profile Manager (nsProfile.cpp)
00587  * INPUT: The specific profile path (prefPath) and the 5.0 installed path
00588  * OUTPUT: The modified 5.0 prefs files
00589  * RETURN: Success or a failure code
00590  *
00591  *-------------------------------------------------------------------------*/
00592 nsresult
00593 nsDogbertProfileMigrator::ProcessPrefsCallback(const char* oldProfilePathStr, const char * newProfilePathStr)
00594 { 
00595   nsresult rv;
00596   
00597   nsCOMPtr<nsIFileSpec> oldProfilePath;
00598   nsCOMPtr<nsIFileSpec> newProfilePath; 
00599   nsCOMPtr<nsIFileSpec> oldPOPMailPath;
00600   nsCOMPtr<nsIFileSpec> newPOPMailPath;
00601   nsCOMPtr<nsIFileSpec> oldIMAPMailPath;
00602   nsCOMPtr<nsIFileSpec> newIMAPMailPath;
00603   nsCOMPtr<nsIFileSpec> oldIMAPLocalMailPath;
00604   nsCOMPtr<nsIFileSpec> newIMAPLocalMailPath;
00605   nsCOMPtr<nsIFileSpec> oldNewsPath;
00606   nsCOMPtr<nsIFileSpec> newNewsPath;
00607   nsCOMPtr<nsILocalFile> newPrefsFile;
00608 #ifdef HAVE_MOVEMAIL
00609   nsCOMPtr<nsIFileSpec> oldMOVEMAILMailPath;
00610   nsCOMPtr<nsIFileSpec> newMOVEMAILMailPath;
00611 #endif /* HAVE_MOVEMAIL */
00612   PRBool exists                  = PR_FALSE, 
00613          enoughSpace             = PR_TRUE,
00614          localMailDriveDefault   = PR_FALSE,
00615          summaryMailDriveDefault = PR_FALSE,
00616          newsDriveDefault        = PR_FALSE,
00617          copyMailFileInMigration = PR_TRUE;
00618 
00619   nsFileSpec localMailSpec,
00620              summaryMailSpec,
00621              newsSpec, 
00622              oldProfileSpec, newProfileSpec;
00623 
00624   PRInt32 serverType = POP_4X_MAIL_TYPE; 
00625   char *popServerName = nsnull;
00626 
00627   PRUint32 totalLocalMailSize = 0,
00628            totalSummaryFileSize = 0,
00629            totalNewsSize = 0, 
00630            totalProfileSize = 0,
00631            totalRequired = 0;
00632 
00633 
00634   PRInt64  localMailDrive   = LL_Zero(),
00635            summaryMailDrive = LL_Zero(),
00636            newsDrive        = LL_Zero(),
00637            profileDrive     = LL_Zero();
00638 
00639   PRInt64  DriveID[MAX_DRIVES];
00640   PRUint32 SpaceRequired[MAX_DRIVES];
00641   
00642 #if defined(NS_DEBUG)
00643   printf("*Entered Actual Migration routine*\n");
00644 #endif
00645 
00646   for (int i=0; i < MAX_DRIVES; i++)
00647   {
00648     DriveID[i] = LL_Zero();
00649     SpaceRequired[i] = 0;
00650   }
00651   
00652   rv = NS_NewFileSpec(getter_AddRefs(oldProfilePath));
00653   if (NS_FAILED(rv)) return rv;
00654   rv = NS_NewFileSpec(getter_AddRefs(newProfilePath));
00655   if (NS_FAILED(rv)) return rv;
00656       
00657   rv = ConvertPersistentStringToFileSpec(oldProfilePathStr, oldProfilePath);
00658   if (NS_FAILED(rv)) return rv;
00659   rv = ConvertPersistentStringToFileSpec(newProfilePathStr, newProfilePath);
00660   if (NS_FAILED(rv)) return rv;
00661 
00662   oldProfilePath->GetFileSpec(&oldProfileSpec);
00663   newProfilePath->GetFileSpec(&newProfileSpec);
00664   
00665   /* initialize prefs with the old prefs.js file (which is a copy of the 4.x preferences file) */
00666   nsCOMPtr<nsIFileSpec> PrefsFile4x;
00667 
00668   //Get the location of the 4.x prefs file
00669   rv = NS_NewFileSpec(getter_AddRefs(PrefsFile4x));
00670   if (NS_FAILED(rv)) return rv;
00671   
00672   rv = PrefsFile4x->FromFileSpec(oldProfilePath);
00673   if (NS_FAILED(rv)) return rv;
00674 
00675   rv = PrefsFile4x->AppendRelativeUnixPath(PREF_FILE_NAME_IN_4x);
00676   if (NS_FAILED(rv)) return rv;
00677 
00678   //Need to convert PrefsFile4x to an IFile in order to copy it to a 
00679   //unique name in the system temp directory.
00680   nsFileSpec PrefsFile4xAsFileSpec;
00681   rv = PrefsFile4x->GetFileSpec(&PrefsFile4xAsFileSpec);
00682   if (NS_FAILED(rv)) return rv;
00683   
00684   nsCOMPtr<nsILocalFile> PrefsFile4xAsIFile;
00685   rv = NS_FileSpecToIFile(&PrefsFile4xAsFileSpec,
00686                      getter_AddRefs(PrefsFile4xAsIFile));
00687   if (NS_FAILED(rv)) return rv;
00688 
00689   nsCOMPtr<nsIFile> systemTempDir;
00690   rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(systemTempDir));
00691   if (NS_FAILED(rv)) return rv;
00692 
00693   systemTempDir->AppendNative(NS_LITERAL_CSTRING("migrate"));
00694   
00695   //Create a unique directory in the system temp dir based on the name of the 4.x prefs file
00696   rv = systemTempDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700); 
00697   if (NS_FAILED(rv)) return rv;
00698 
00699   rv = PrefsFile4xAsIFile->CopyToNative(systemTempDir, NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
00700   if (NS_FAILED(rv)) return rv;
00701   
00702   nsCOMPtr<nsIFile> cloneFile;
00703   rv = systemTempDir->Clone(getter_AddRefs(cloneFile));
00704   if (NS_FAILED(rv)) return rv;
00705 
00706   m_prefsFile = do_QueryInterface(cloneFile, &rv);
00707   if (NS_FAILED(rv)) return rv;
00708 
00709   rv = m_prefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
00710   if (NS_FAILED(rv)) return rv;
00711 
00712   //Clear the prefs in case a previous set was read in.
00713   mPrefs->ResetPrefs();
00714 
00715   //Now read the prefs from the prefs file in the system directory
00716   mPrefs->ReadUserPrefs(m_prefsFile);
00717 
00718   // Start computing the sizes required for migration
00719   //
00720   rv = GetSizes(oldProfileSpec, PR_FALSE, &totalProfileSize);
00721   profileDrive = newProfileSpec.GetDiskSpaceAvailable();
00722 
00723   rv = mPrefs->GetIntPref(PREF_MAIL_SERVER_TYPE, &serverType);
00724   if (NS_FAILED(rv)) return rv;
00725 
00726   // get the migration mode for mail
00727   rv = mPrefs->GetBoolPref(PREF_MIGRATION_MODE_FOR_MAIL, &copyMailFileInMigration);
00728   if (NS_FAILED(rv))
00729     return rv;
00730 
00731   if (serverType == POP_4X_MAIL_TYPE) {
00732     summaryMailDriveDefault = PR_TRUE; //summary files are only used in IMAP so just set it to true here.
00733     summaryMailDrive = profileDrive;   //just set the drive for summary files to be the same as the new profile
00734 
00735     rv = NS_NewFileSpec(getter_AddRefs(newPOPMailPath));
00736     if (NS_FAILED(rv)) return rv;
00737 
00738     rv = NS_NewFileSpec(getter_AddRefs(oldPOPMailPath));
00739     if (NS_FAILED(rv)) return rv;
00740     
00741     rv = GetDirFromPref(oldProfilePath,newProfilePath,NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY, newPOPMailPath, oldPOPMailPath);
00742     if (NS_FAILED(rv)) {
00743       rv = DetermineOldPath(oldProfilePath, OLD_MAIL_DIR_NAME, "mailDirName", oldPOPMailPath);
00744       if (NS_FAILED(rv)) return rv;
00745 
00746       rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldPOPMailPath);
00747       if (NS_FAILED(rv)) return rv;
00748 
00749       rv = newPOPMailPath->FromFileSpec(newProfilePath);
00750       if (NS_FAILED(rv)) return rv;
00751 
00752       localMailDriveDefault = PR_TRUE;
00753     }
00754     oldPOPMailPath->GetFileSpec(&localMailSpec);
00755     rv = GetSizes(localMailSpec, PR_TRUE, &totalLocalMailSize);
00756     localMailDrive = localMailSpec.GetDiskSpaceAvailable();
00757   }
00758   else if(serverType == IMAP_4X_MAIL_TYPE) {
00759     rv = NS_NewFileSpec(getter_AddRefs(newIMAPLocalMailPath));
00760     if (NS_FAILED(rv)) return rv;
00761       
00762     rv = NS_NewFileSpec(getter_AddRefs(oldIMAPLocalMailPath));
00763     if (NS_FAILED(rv)) return rv;
00764         
00765     /* First get the actual 4.x "Local Mail" files location */
00766     rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY, newIMAPLocalMailPath, oldIMAPLocalMailPath);
00767     if (NS_FAILED(rv)) {
00768       rv = DetermineOldPath(oldProfilePath, OLD_MAIL_DIR_NAME, "mailDirName", oldIMAPLocalMailPath);
00769       if (NS_FAILED(rv)) return rv;
00770 
00771       rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldIMAPLocalMailPath);
00772       if (NS_FAILED(rv)) return rv;
00773 
00774       rv = newIMAPLocalMailPath->FromFileSpec(newProfilePath);
00775       if (NS_FAILED(rv)) return rv;
00776       
00777       localMailDriveDefault = PR_TRUE;
00778     }
00779 
00780     oldIMAPLocalMailPath->GetFileSpec(&localMailSpec);
00781     rv = GetSizes(localMailSpec, PR_TRUE, &totalLocalMailSize);
00782     localMailDrive = localMailSpec.GetDiskSpaceAvailable();
00783 
00784     /* Next get IMAP mail summary files location */
00785     rv = NS_NewFileSpec(getter_AddRefs(newIMAPMailPath));
00786     if (NS_FAILED(rv)) return rv;
00787     
00788     rv = NS_NewFileSpec(getter_AddRefs(oldIMAPMailPath));
00789     if (NS_FAILED(rv)) return rv;
00790 
00791     rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_IMAPMAIL_DIR_NAME, PREF_MAIL_IMAP_ROOT_DIR,newIMAPMailPath,oldIMAPMailPath);
00792     if (NS_FAILED(rv)) {
00793       rv = oldIMAPMailPath->FromFileSpec(oldProfilePath);
00794       if (NS_FAILED(rv)) return rv;
00795         
00796       /* we didn't over localize "ImapMail" in 4.x, so this is all we have to do */
00797       rv = oldIMAPMailPath->AppendRelativeUnixPath(OLD_IMAPMAIL_DIR_NAME);
00798       if (NS_FAILED(rv)) return rv;
00799 
00800       rv = SetPremigratedFilePref(PREF_MAIL_IMAP_ROOT_DIR, oldIMAPMailPath);
00801       if (NS_FAILED(rv)) return rv;   
00802       
00803       rv = newIMAPMailPath->FromFileSpec(newProfilePath);
00804       if (NS_FAILED(rv)) return rv;
00805 
00806       summaryMailDriveDefault = PR_TRUE;
00807     }
00808 
00809     oldIMAPMailPath->GetFileSpec(&summaryMailSpec);
00810     rv = GetSizes(summaryMailSpec, PR_TRUE, &totalSummaryFileSize);
00811     summaryMailDrive = summaryMailSpec.GetDiskSpaceAvailable();
00812   }   
00813 
00814 #ifdef HAVE_MOVEMAIL
00815   else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
00816     
00817     summaryMailDriveDefault = PR_TRUE;
00818     summaryMailDrive = profileDrive;
00819 
00820     rv = NS_NewFileSpec(getter_AddRefs(newMOVEMAILMailPath));
00821     if (NS_FAILED(rv)) return rv;
00822 
00823     rv = NS_NewFileSpec(getter_AddRefs(oldMOVEMAILMailPath));
00824     if (NS_FAILED(rv)) return rv;
00825     
00826     rv = GetDirFromPref(oldProfilePath,newProfilePath,NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY, newMOVEMAILMailPath, oldMOVEMAILMailPath);
00827     if (NS_FAILED(rv)) {
00828       rv = oldMOVEMAILMailPath->FromFileSpec(oldProfilePath);
00829       if (NS_FAILED(rv)) return rv;
00830 
00831       /* we didn't over localize this in 4.x, so this is all we have to do */
00832       rv = oldMOVEMAILMailPath->AppendRelativeUnixPath(OLD_MAIL_DIR_NAME);
00833       if (NS_FAILED(rv)) return rv;
00834       
00835       rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldMOVEMAILMailPath);
00836       if (NS_FAILED(rv)) return rv;
00837 
00838       rv = newMOVEMAILMailPath->FromFileSpec(newProfilePath);
00839       if (NS_FAILED(rv)) return rv;
00840 
00841       localMailDriveDefault = PR_TRUE;
00842     }
00843     oldMOVEMAILMailPath->GetFileSpec(&localMailSpec);
00844     rv = GetSizes(localMailSpec, PR_TRUE, &totalLocalMailSize);
00845 
00846     localMailDrive = localMailSpec.GetDiskSpaceAvailable();
00847    
00848   }    
00849 #endif //HAVE_MOVEMAIL
00850 
00852     // Now get the NEWS disk space requirements for migration.
00854     rv = NS_NewFileSpec(getter_AddRefs(newNewsPath));
00855     if (NS_FAILED(rv)) return rv;
00856     
00857     rv = NS_NewFileSpec(getter_AddRefs(oldNewsPath));
00858     if (NS_FAILED(rv)) return rv;
00859     
00860     rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_NEWS_DIR_NAME, PREF_NEWS_DIRECTORY, newNewsPath,oldNewsPath);
00861     if (NS_FAILED(rv)) {
00862       rv = DetermineOldPath(oldProfilePath, OLD_NEWS_DIR_NAME, "newsDirName", oldNewsPath);
00863       if (NS_FAILED(rv)) return rv;
00864 
00865       rv = SetPremigratedFilePref(PREF_NEWS_DIRECTORY, oldNewsPath);
00866       if (NS_FAILED(rv)) return rv; 
00867 
00868       rv = newNewsPath->FromFileSpec(newProfilePath);
00869       if (NS_FAILED(rv)) return rv;
00870 
00871       newsDriveDefault = PR_TRUE;
00872     }
00873     oldNewsPath->GetFileSpec(&newsSpec);
00874     rv = GetSizes(newsSpec, PR_TRUE, &totalNewsSize);
00875     newsDrive = newsSpec.GetDiskSpaceAvailable();
00876 
00877     // 
00878     // Compute the space needed to migrate the profile
00879     //
00880     if(newsDriveDefault && localMailDriveDefault && summaryMailDriveDefault) // DEFAULT: All on the same drive
00881     {
00882       totalRequired = totalNewsSize + totalLocalMailSize + totalSummaryFileSize + totalProfileSize;
00883       rv = ComputeSpaceRequirements(DriveID, SpaceRequired, profileDrive, totalRequired);
00884       if (NS_FAILED(rv))
00885         enoughSpace = PR_FALSE;
00886     }
00887     else
00888     {
00889       rv = ComputeSpaceRequirements(DriveID, SpaceRequired, profileDrive, totalProfileSize);
00890       if (NS_FAILED(rv))
00891         enoughSpace = PR_FALSE;
00892       rv = ComputeSpaceRequirements(DriveID, SpaceRequired, localMailDrive, totalLocalMailSize);
00893       if (NS_FAILED(rv))
00894         enoughSpace = PR_FALSE;
00895       rv = ComputeSpaceRequirements(DriveID, SpaceRequired, summaryMailDrive, totalSummaryFileSize);
00896       if (NS_FAILED(rv))
00897         enoughSpace = PR_FALSE;
00898       rv = ComputeSpaceRequirements(DriveID, SpaceRequired, newsDrive, totalNewsSize);
00899       if (NS_FAILED(rv))
00900         enoughSpace = PR_FALSE;
00901     }
00902 
00903     // do something if not enough space
00904 
00906   // If we reached this point, there is enough room to do a migration.
00907   // Start creating directories and setting new pref values.
00909 
00910   /* Create the new profile tree for 5.x */
00911   rv = CreateNewUser5Tree(oldProfilePath, newProfilePath);
00912   if (NS_FAILED(rv)) return rv;
00913 
00914   
00915   if (serverType == POP_4X_MAIL_TYPE) {
00916 
00917     rv = newPOPMailPath->Exists(&exists);
00918     if (NS_FAILED(rv)) return rv;
00919     if (!exists)  {
00920       rv = newPOPMailPath->CreateDir();
00921       if (NS_FAILED(rv)) return rv;
00922     }
00923 
00924     rv = newPOPMailPath->AppendRelativeUnixPath(NEW_MAIL_DIR_NAME);
00925     if (NS_FAILED(rv)) return rv;
00926  
00927     rv = newPOPMailPath->Exists(&exists);
00928     if (NS_FAILED(rv)) return rv;
00929     if (!exists)  {
00930       rv = newPOPMailPath->CreateDir();
00931       if (NS_FAILED(rv)) return rv;
00932     }
00933 
00934     {
00935       // temporarily go through nsFileSpec
00936       nsFileSpec newPOPMailPathSpec;
00937       newPOPMailPath->GetFileSpec(&newPOPMailPathSpec);
00938       
00939       nsCOMPtr<nsILocalFile> newPOPMailPathFile;
00940       NS_FileSpecToIFile(&newPOPMailPathSpec,
00941                          getter_AddRefs(newPOPMailPathFile));
00942       
00943       rv = mPrefs->SetFileXPref(PREF_MAIL_DIRECTORY, newPOPMailPathFile); 
00944       if (NS_FAILED(rv)) return rv;
00945     }
00946 
00947     mPrefs->CopyCharPref(PREF_NETWORK_HOSTS_POP_SERVER, &popServerName);
00948 
00949     nsCAutoString popServerNamewithoutPort(popServerName);
00950     PRInt32 colonPos = popServerNamewithoutPort.FindChar(':');
00951 
00952     if (colonPos != -1 ) {
00953            popServerNamewithoutPort.Truncate(colonPos);
00954            rv = newPOPMailPath->AppendRelativeUnixPath(popServerNamewithoutPort.get());
00955     }
00956     else {
00957            rv = newPOPMailPath->AppendRelativeUnixPath(popServerName);
00958     }
00959 
00960     if (NS_FAILED(rv)) return rv;                         
00961     
00962     rv = newPOPMailPath->Exists(&exists);
00963     if (NS_FAILED(rv)) return rv;
00964     if (!exists)  {
00965       rv = newPOPMailPath->CreateDir();
00966       if (NS_FAILED(rv)) return rv;
00967     }
00968   }
00969   else if (serverType == IMAP_4X_MAIL_TYPE) {
00970    if( copyMailFileInMigration )  // copy mail files in migration 
00971    {
00972      rv = newIMAPLocalMailPath->Exists(&exists);
00973      if (NS_FAILED(rv)) return rv;
00974      if (!exists)  {
00975         rv = newIMAPLocalMailPath->CreateDir();
00976         if (NS_FAILED(rv)) return rv;
00977      }
00978       
00979     rv = newIMAPLocalMailPath->AppendRelativeUnixPath(NEW_MAIL_DIR_NAME);
00980     if (NS_FAILED(rv)) return rv;
00981 
00982     /* Now create the new "Mail/Local Folders" directory */
00983     rv = newIMAPLocalMailPath->Exists(&exists);
00984     if (NS_FAILED(rv)) return rv;
00985     if (!exists)  {
00986       newIMAPLocalMailPath->CreateDir();
00987     }
00988 
00989     {
00990       // temporarily go through nsFileSpec
00991       nsFileSpec newIMAPLocalMailPathSpec;
00992       newIMAPLocalMailPath->GetFileSpec(&newIMAPLocalMailPathSpec);
00993       
00994       nsCOMPtr<nsILocalFile> newIMAPLocalMailPathFile;
00995       NS_FileSpecToIFile(&newIMAPLocalMailPathSpec,
00996                          getter_AddRefs(newIMAPLocalMailPathFile));
00997       
00998       rv = mPrefs->SetFileXPref(PREF_MAIL_DIRECTORY, newIMAPLocalMailPathFile); 
00999       if (NS_FAILED(rv)) return rv;
01000     }
01001 
01002     rv = newIMAPLocalMailPath->AppendRelativeUnixPath(NEW_LOCAL_MAIL_DIR_NAME);
01003     if (NS_FAILED(rv)) return rv;
01004     rv = newIMAPLocalMailPath->Exists(&exists);
01005     if (NS_FAILED(rv)) return rv;
01006     if (!exists)  {
01007       rv = newIMAPLocalMailPath->CreateDir();
01008       if (NS_FAILED(rv)) return rv;
01009     }
01010 
01011     /* Now deal with the IMAP mail summary file location */
01012     rv = newIMAPMailPath->Exists(&exists);
01013     if (NS_FAILED(rv)) return rv;
01014     if (!exists)  {
01015       rv = newIMAPMailPath->CreateDir();
01016       if (NS_FAILED(rv)) return rv;
01017     }
01018 
01019     rv = newIMAPMailPath->AppendRelativeUnixPath(NEW_IMAPMAIL_DIR_NAME);
01020     if (NS_FAILED(rv)) return rv;
01021 
01022     rv = newIMAPMailPath->Exists(&exists);
01023     if (NS_FAILED(rv)) return rv;
01024     if (!exists)  {
01025       rv = newIMAPMailPath->CreateDir();
01026       if (NS_FAILED(rv)) return rv;
01027     }
01028 
01029     {
01030       // temporarily go through nsFileSpec
01031       nsFileSpec newIMAPMailPathSpec;
01032       newIMAPMailPath->GetFileSpec(&newIMAPMailPathSpec);
01033       
01034       nsCOMPtr<nsILocalFile> newIMAPMailPathFile;
01035       NS_FileSpecToIFile(&newIMAPMailPathSpec,
01036                          getter_AddRefs(newIMAPMailPathFile));
01037       
01038       rv = mPrefs->SetFileXPref(PREF_MAIL_IMAP_ROOT_DIR, newIMAPMailPathFile);
01039       if (NS_FAILED(rv)) return rv;
01040     }
01041    }
01042    else
01043    {
01044     {
01045       // temporarily go through nsFileSpec
01046       nsFileSpec oldIMAPLocalMailPathSpec;
01047       oldIMAPLocalMailPath->GetFileSpec(&oldIMAPLocalMailPathSpec);
01048 
01049       nsCOMPtr<nsILocalFile> oldIMAPLocalMailPathFile;
01050       NS_FileSpecToIFile(&oldIMAPLocalMailPathSpec,
01051                          getter_AddRefs(oldIMAPLocalMailPathFile));
01052 
01053       rv = mPrefs->SetFileXPref(PREF_MAIL_DIRECTORY, oldIMAPLocalMailPathFile);
01054       if (NS_FAILED(rv)) return rv;
01055     }
01056     {
01057       // temporarily go through nsFileSpec
01058       nsFileSpec oldIMAPMailPathSpec;
01059       oldIMAPMailPath->GetFileSpec(&oldIMAPMailPathSpec);
01060 
01061       nsCOMPtr<nsILocalFile> oldIMAPMailPathFile;
01062       NS_FileSpecToIFile(&oldIMAPMailPathSpec,
01063                          getter_AddRefs(oldIMAPMailPathFile));
01064 
01065       rv = mPrefs->SetFileXPref(PREF_MAIL_IMAP_ROOT_DIR, oldIMAPMailPathFile);
01066       if (NS_FAILED(rv)) return rv;
01067     }
01068    }
01069   }
01070 
01071 #ifdef HAVE_MOVEMAIL
01072   else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
01073 
01074     rv = newMOVEMAILMailPath->Exists(&exists);
01075     if (NS_FAILED(rv)) return rv;
01076     if (!exists)  {
01077       rv = newMOVEMAILMailPath->CreateDir();
01078       if (NS_FAILED(rv)) return rv;
01079     }
01080 
01081     rv = newMOVEMAILMailPath->AppendRelativeUnixPath(NEW_MAIL_DIR_NAME);
01082     if (NS_FAILED(rv)) return rv;
01083 
01084     rv = newMOVEMAILMailPath->Exists(&exists);
01085     if (NS_FAILED(rv)) return rv;
01086     if (!exists)  {
01087       rv = newMOVEMAILMailPath->CreateDir();
01088       if (NS_FAILED(rv)) return rv;
01089     }
01090 
01091     {
01092       // temporarily go through nsFileSpec
01093       nsFileSpec newMOVEMAILPathSpec;
01094       newMOVEMAILMailPath->GetFileSpec(&newMOVEMAILPathSpec);
01095       
01096       nsCOMPtr<nsILocalFile> newMOVEMAILPathFile;
01097       NS_FileSpecToIFile(&newMOVEMAILPathSpec,
01098                          getter_AddRefs(newMOVEMAILPathFile));
01099       
01100       rv = mPrefs->SetFileXPref(PREF_MAIL_DIRECTORY, newMOVEMAILPathFile); 
01101       if (NS_FAILED(rv)) return rv;
01102     }
01103 
01104     rv = newMOVEMAILMailPath->AppendRelativeUnixPath(NEW_MOVEMAIL_DIR_NAME);
01105     if (NS_FAILED(rv)) return rv;
01106 
01107     rv = newMOVEMAILMailPath->Exists(&exists);
01108     if (NS_FAILED(rv)) return rv;
01109     if (!exists)  {
01110       rv = newMOVEMAILMailPath->CreateDir();
01111       if (NS_FAILED(rv)) return rv;
01112     }
01113     rv = NS_OK;
01114   }
01115 #endif /* HAVE_MOVEMAIL */
01116   else {
01117     NS_ASSERTION(0,"failure, didn't recognize your mail server type.\n");
01118     return NS_ERROR_UNEXPECTED;
01119   }
01120   
01122   // Set all the appropriate NEWS prefs.
01124 
01125   rv = newNewsPath->Exists(&exists);
01126   if (NS_FAILED(rv)) return rv;
01127   if (!exists)  {
01128     rv = newNewsPath->CreateDir();
01129     if (NS_FAILED(rv)) return rv;
01130   }
01131 
01132   rv = newNewsPath->AppendRelativeUnixPath(NEW_NEWS_DIR_NAME);
01133   if (NS_FAILED(rv)) return rv;
01134 
01135   rv = newNewsPath->Exists(&exists);
01136   if (NS_FAILED(rv)) return rv;
01137   if (!exists)  {
01138     rv = newNewsPath->CreateDir();
01139     if (NS_FAILED(rv)) return rv;
01140   }
01141 
01142   {
01143     // temporarily go through nsFileSpec
01144     nsFileSpec newNewsPathSpec;
01145     newNewsPath->GetFileSpec(&newNewsPathSpec);
01146     
01147     nsCOMPtr<nsILocalFile> newNewsPathFile;
01148     NS_FileSpecToIFile(&newNewsPathSpec,
01149                        getter_AddRefs(newNewsPathFile));
01150     
01151     rv = mPrefs->SetFileXPref(PREF_NEWS_DIRECTORY, newNewsPathFile); 
01152     if (NS_FAILED(rv)) return rv;
01153   }
01154 
01155   PRBool needToRenameFilterFiles;
01156   if (PL_strcmp(IMAP_MAIL_FILTER_FILE_NAME_IN_4x,IMAP_MAIL_FILTER_FILE_NAME_IN_5x)) {
01157 #ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
01158     // if we defined a format, the filter files don't live in the host directories
01159     // (mac does this.)  we'll take care of those filter files later, in DoSpecialUpdates()
01160     needToRenameFilterFiles = PR_FALSE;
01161 #else
01162     needToRenameFilterFiles = PR_TRUE;
01163 #endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
01164   }
01165   else {
01166     // if the name was the same in 4x as in 5x, no need to rename it
01167     needToRenameFilterFiles = PR_FALSE;
01168   }
01169   
01170   // just copy what we need
01171 #if defined(XP_MAC) || defined(XP_MACOSX)
01172   rv = DoTheCopy(oldProfilePath, newProfilePath, SECURITY_PATH, PR_TRUE);
01173   if (NS_FAILED(rv)) return rv;
01174 #else
01175   rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_CERT7_DB);
01176   if (NS_FAILED(rv)) return rv;
01177   rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_KEY3_DB);
01178   if (NS_FAILED(rv)) return rv;
01179   rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_SECMODULE_DB);
01180   if (NS_FAILED(rv)) return rv;
01181 #endif /* XP_MAC */
01182 
01183   // Copy the addrbook files.
01184   rv = CopyFilesByPattern(oldProfilePath, newProfilePath, ADDRBOOK_FILE_EXTENSION_IN_4X);
01185   NS_ENSURE_SUCCESS(rv,rv);
01186 
01187 #if defined(XP_MAX) || defined(XP_MACOSX)
01188   // Copy the Mac filter rule files which sits at the top level dir of a 4.x profile.
01189   if(serverType == IMAP_4X_MAIL_TYPE) {
01190     rv = CopyFilesByPattern(oldProfilePath, newProfilePath, MAC_RULES_FILE_ENDING_STRING_IN_4X);
01191     NS_ENSURE_SUCCESS(rv,rv);
01192   }
01193 #endif
01194 
01195   rv = DoTheCopy(oldNewsPath, newNewsPath, PR_TRUE);
01196   if (NS_FAILED(rv)) return rv;
01197 
01198 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
01199   /* in 4.x, the newsrc files were in $HOME.  Now that we can have multiple
01200    * profiles in 5.x, with the same user, this won't fly.
01201    * when they migrate, we need to copy from $HOME/.newsrc-<host> to
01202    * ~/.mozilla/<profile>/News/newsrc-<host>
01203    */
01204   rv = CopyAndRenameNewsrcFiles(newNewsPath);
01205   if (NS_FAILED(rv)) return rv;
01206 #endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
01207 
01208   if (serverType == IMAP_4X_MAIL_TYPE) {
01209     if( copyMailFileInMigration )  // copy mail files in migration
01210     {
01211     rv = DoTheCopyAndRename(oldIMAPMailPath, newIMAPMailPath, PR_TRUE, needToRenameFilterFiles, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
01212     if (NS_FAILED(rv)) return rv;
01213     rv = DoTheCopyAndRename(oldIMAPLocalMailPath, newIMAPLocalMailPath, PR_TRUE, needToRenameFilterFiles,IMAP_MAIL_FILTER_FILE_NAME_IN_4x,IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
01214     if (NS_FAILED(rv)) return rv;
01215     }
01216     else  // Copy & Rename filter files
01217     {
01218       // IMAP path
01219       // don't care if this fails
01220       (void)DoTheCopyAndRename(oldIMAPMailPath, PR_TRUE, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
01221       
01222       // Local Folders path
01223       // don't care if this fails
01224       (void)DoTheCopyAndRename(oldIMAPLocalMailPath, PR_TRUE, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
01225     }
01226   }
01227   else if (serverType == POP_4X_MAIL_TYPE) {
01228     // fix for bug #202010
01229     // copy over the pop filter and popstate files now
01230     // and later, in DoSpecialUpdates()
01231     // we'll move and rename them
01232 #ifdef POP_MAIL_FILTER_FILE_NAME_IN_4x
01233     rv = DoTheCopy(oldProfilePath, newProfilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x);
01234     if (NS_FAILED(rv)) return rv;
01235 #endif
01236     
01237 #ifdef POPSTATE_FILE_IN_4x 
01238     rv = DoTheCopy(oldProfilePath, newProfilePath, POPSTATE_FILE_IN_4x);
01239     if (NS_FAILED(rv)) return rv;
01240 #endif
01241     
01242     rv = DoTheCopy(oldPOPMailPath, newPOPMailPath, PR_TRUE);
01243     if (NS_FAILED(rv)) return rv;
01244   }
01245 #ifdef HAVE_MOVEMAIL
01246   else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
01247     // in 4.x, the movemail filter name was the same as the pop filter name
01248     // copy over the filter file now
01249     // and later, in DoSpecialUpdates()
01250     // we'll move and rename them
01251     rv = DoTheCopy(oldProfilePath, newProfilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x);
01252     if (NS_FAILED(rv)) return rv;
01253     
01254     rv = DoTheCopy(oldMOVEMAILMailPath, newMOVEMAILMailPath, PR_TRUE);
01255   }
01256 #endif /* HAVE_MOVEMAIL */
01257   else {
01258     NS_ASSERTION(0, "unknown mail server type!");
01259     return NS_ERROR_FAILURE;
01260   }
01261   
01262   // Don't inherit the 4.x cache file location for mozilla!
01263   // The cache pref later gets set with a default in nsAppRunner::InitCachePrefs().
01264   mPrefs->ClearUserPref(PREF_BROWSER_CACHE_DIRECTORY);
01265 
01266   rv = DoSpecialUpdates(newProfilePath);
01267   if (NS_FAILED(rv)) return rv;
01268     PR_FREEIF(popServerName);
01269 
01270   nsXPIDLCString path;
01271 
01272   newProfilePath->GetNativePath(getter_Copies(path));
01273   NS_NewNativeLocalFile(path, PR_TRUE, getter_AddRefs(newPrefsFile));
01274 
01275   rv = newPrefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_5x));
01276   if (NS_FAILED(rv)) return rv;
01277 
01278   rv=mPrefs->SavePrefFile(newPrefsFile);
01279   if (NS_FAILED(rv)) return rv;
01280   rv=mPrefs->ResetPrefs();
01281   if (NS_FAILED(rv)) return rv;
01282 
01283   PRBool flagExists = PR_FALSE;
01284   m_prefsFile->Exists(&flagExists); //Delete the prefs.js file in the temp directory.
01285   if (flagExists)
01286     m_prefsFile->Remove(PR_FALSE);
01287   
01288   systemTempDir->Exists(&flagExists); //Delete the unique dir in the system temp dir.
01289   if (flagExists)
01290     systemTempDir->Remove(PR_FALSE);
01291 
01292   return rv;
01293 }
01294 
01295 nsresult nsDogbertProfileMigrator::CreateNewUser5Tree(nsIFileSpec * oldProfilePath, nsIFileSpec * newProfilePath)
01296 {
01297   nsresult rv;
01298   PRBool exists;
01299   
01300   NS_ASSERTION(*PREF_FILE_NAME_IN_4x, "don't know how to migrate your platform");
01301   if (!*PREF_FILE_NAME_IN_4x) {
01302     return NS_ERROR_UNEXPECTED;
01303   }
01304       
01305   /* Copy the old prefs file to the new profile directory for modification and reading.  
01306      after copying it, rename it to pref.js, the 5.x pref file name on all platforms */
01307   nsCOMPtr<nsIFileSpec> oldPrefsFile;
01308   rv = NS_NewFileSpec(getter_AddRefs(oldPrefsFile)); 
01309   if (NS_FAILED(rv)) return rv;
01310   
01311   rv = oldPrefsFile->FromFileSpec(oldProfilePath);
01312   if (NS_FAILED(rv)) return rv;
01313   
01314   rv = oldPrefsFile->AppendRelativeUnixPath(PREF_FILE_NAME_IN_4x);
01315   if (NS_FAILED(rv)) return rv;
01316 
01317   /* the new prefs file */
01318   nsCOMPtr<nsIFileSpec> newPrefsFile;
01319   rv = NS_NewFileSpec(getter_AddRefs(newPrefsFile)); 
01320   if (NS_FAILED(rv)) return rv;
01321   
01322   rv = newPrefsFile->FromFileSpec(newProfilePath);
01323   if (NS_FAILED(rv)) return rv;
01324   
01325   rv = newPrefsFile->Exists(&exists);
01326   if (!exists)
01327   {
01328          rv = newPrefsFile->CreateDir();
01329   }
01330 
01331   rv = oldPrefsFile->CopyToDir(newPrefsFile);
01332   NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy prefs file");
01333 
01334   rv = newPrefsFile->AppendRelativeUnixPath(PREF_FILE_NAME_IN_4x);
01335   rv = newPrefsFile->Rename(PREF_FILE_NAME_IN_5x);
01336 
01337   return NS_OK;
01338 }
01339 
01340 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
01341 nsresult nsDogbertProfileMigrator::CopyAndRenameNewsrcFiles(nsIFileSpec * newPathSpec)
01342 {
01343   nsresult rv;
01344   nsCOMPtr <nsIFileSpec>oldPathSpec;
01345   nsFileSpec oldPath;
01346   nsFileSpec newPath;
01347   char* folderName = nsnull;
01348   nsCAutoString fileOrDirNameStr;
01349 
01350   rv = GetPremigratedFilePref(PREF_NEWS_DIRECTORY, getter_AddRefs(oldPathSpec));
01351   if (NS_FAILED(rv)) return rv;
01352   rv = oldPathSpec->GetFileSpec(&oldPath);
01353   if (NS_FAILED(rv)) return rv;
01354   rv = newPathSpec->GetFileSpec(&newPath);
01355   if (NS_FAILED(rv)) return rv;
01356 
01357   for (nsDirectoryIterator dir(oldPath, PR_FALSE); dir.Exists(); dir++)
01358   {
01359     nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
01360     folderName = fileOrDirName.GetLeafName();    //get the filename without the full path
01361     fileOrDirNameStr.Assign(folderName);
01362 
01363     if (nsCStringStartsWith(fileOrDirNameStr, NEWSRC_PREFIX_IN_4x) || nsCStringStartsWith(fileOrDirNameStr, SNEWSRC_PREFIX_IN_4x)) {
01364 #ifdef DEBUG_seth
01365            printf("newsrc file == %s\n",folderName);
01366 #endif /* DEBUG_seth */
01367 
01368            rv = fileOrDirName.CopyToDir(newPath);
01369         NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy news file");
01370 
01371         nsFileSpec newFile = newPath;
01372         newFile += fileOrDirNameStr.get();
01373         newFile.Rename(folderName + 1); /* rename .newsrc-news to newsrc-news, no need to keep it hidden anymore */
01374     }
01375   }
01376 
01377   return NS_OK;
01378 }
01379 #endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
01380 
01381 
01382 /*-------------------------------------------------------------------------
01383  * DoTheCopyAndRename copies the files listed in oldPath to newPath
01384  *                    and renames files, if necessary
01385  *
01386  * INPUT: oldPath - The old profile path plus the specific data type 
01387  *                  (e.g. mail or news)
01388  *        newPath - The new profile path plus the specific data type
01389  *
01390  *        readSubdirs
01391  *
01392  *        needToRenameFiles - do we need to search for files named oldFile
01393  *                            and rename them to newFile
01394  *
01395  *        oldFile           - old file name (used for renaming)
01396  *
01397  *        newFile           - new file name (used for renaming)
01398  *
01399  * RETURNS: NS_OK if successful
01400  *          NS_ERROR_FAILURE if failed
01401  *
01402  *--------------------------------------------------------------------------*/
01403 nsresult nsDogbertProfileMigrator::DoTheCopyAndRename(nsIFileSpec * oldPathSpec, nsIFileSpec *newPathSpec, PRBool readSubdirs, PRBool needToRenameFiles, const char *oldName, const char *newName)
01404 {
01405   nsresult rv;
01406   char* folderName = nsnull;
01407   nsCAutoString fileOrDirNameStr;
01408   nsFileSpec oldPath;
01409   nsFileSpec newPath;
01410   
01411   rv = oldPathSpec->GetFileSpec(&oldPath);
01412   if (NS_FAILED(rv)) return rv;
01413   rv = newPathSpec->GetFileSpec(&newPath);
01414   if (NS_FAILED(rv)) return rv;
01415   
01416   for (nsDirectoryIterator dir(oldPath, PR_FALSE); dir.Exists(); dir++)
01417   {
01418     nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
01419     folderName = fileOrDirName.GetLeafName();    //get the filename without the full path
01420     fileOrDirNameStr.Assign(folderName);
01421 
01422     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 */
01423       continue;
01424     else
01425     {
01426       if (fileOrDirName.IsDirectory())
01427       {
01428         if(readSubdirs)
01429         {
01430           nsCOMPtr<nsIFileSpec> newPathExtended;
01431           rv = NS_NewFileSpecWithSpec(newPath, getter_AddRefs(newPathExtended));
01432           rv = newPathExtended->AppendRelativeUnixPath(folderName);
01433           rv = newPathExtended->CreateDir();
01434           
01435           nsCOMPtr<nsIFileSpec>fileOrDirNameSpec;
01436           rv = NS_NewFileSpecWithSpec(fileOrDirName, getter_AddRefs(fileOrDirNameSpec));
01437           DoTheCopyAndRename(fileOrDirNameSpec, newPathExtended, PR_TRUE, needToRenameFiles, oldName, newName); /* re-enter the DoTheCopyAndRename function */
01438         }
01439         else
01440           continue;
01441       }
01442       else {
01443         // copy the file
01444         if (fileOrDirNameStr.Equals(oldName)) 
01445           AddFileCopyToList(&fileOrDirName, &newPath, newName);
01446         else
01447           AddFileCopyToList(&fileOrDirName, &newPath, "");
01448       }
01449     }
01450   }  
01451   
01452   return NS_OK;
01453 }
01454 
01455 /*-------------------------------------------------------------------------
01456  * DoTheCopyAndRename copies and renames files
01457  *
01458  * INPUT: aPath - the path
01459  *
01460  *        aReadSubdirs - if sub directories should be handled
01461  *
01462  *        aOldFile - old file name (used for renaming)
01463  *
01464  *        aNewFile - new file name (used for renaming)
01465  *
01466  * RETURNS: NS_OK if successful
01467  *          NS_ERROR_FAILURE if failed
01468  *
01469  *--------------------------------------------------------------------------*/
01470 nsresult nsDogbertProfileMigrator::DoTheCopyAndRename(nsIFileSpec * aPathSpec, PRBool aReadSubdirs, const char *aOldName, const char *aNewName)
01471 {
01472   if( !aOldName || !aNewName || !strcmp(aOldName, aNewName) )
01473     return NS_ERROR_FAILURE;
01474 
01475   nsresult rv;
01476   nsFileSpec path, file;
01477   
01478   rv = aPathSpec->GetFileSpec(&path);
01479   if (NS_FAILED(rv))
01480     return rv;
01481   rv = aPathSpec->GetFileSpec(&file);
01482   if (NS_FAILED(rv))
01483     return rv;
01484   file += aOldName;
01485   
01486   // Handle sub folders
01487   for (nsDirectoryIterator dir(path, PR_FALSE); dir.Exists(); dir++)
01488   {
01489     nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
01490     if (fileOrDirName.IsDirectory())
01491     {
01492       if( aReadSubdirs )
01493       {
01494         nsCOMPtr<nsIFileSpec>fileOrDirNameSpec;
01495         rv = NS_NewFileSpecWithSpec(fileOrDirName, getter_AddRefs(fileOrDirNameSpec));
01496         DoTheCopyAndRename(fileOrDirNameSpec, aReadSubdirs, aOldName, aNewName); /* re-enter the DoTheCopyAndRename function */
01497       }
01498       else
01499         continue;
01500     }
01501   }
01502 
01503   nsCOMPtr<nsILocalFile> localFileOld, localFileDirectory;
01504   rv = NS_FileSpecToIFile(&file, getter_AddRefs(localFileOld));
01505   if (NS_FAILED(rv))
01506     return rv;
01507   rv = NS_FileSpecToIFile(&path, getter_AddRefs(localFileDirectory));
01508   if (NS_FAILED(rv))
01509     return rv;
01510   nsAutoString newName = NS_ConvertUTF8toUCS2(aNewName);
01511   localFileOld->CopyTo(localFileDirectory, newName);
01512 
01513   return NS_OK;
01514 }
01515 
01516 nsresult nsDogbertProfileMigrator::CopyFilesByPattern(nsIFileSpec * oldPathSpec, nsIFileSpec * newPathSpec, const char *pattern)
01517 {
01518   nsFileSpec oldPath;
01519   nsFileSpec newPath;
01520   
01521   nsresult rv = oldPathSpec->GetFileSpec(&oldPath);
01522   NS_ENSURE_SUCCESS(rv,rv);
01523   rv = newPathSpec->GetFileSpec(&newPath);
01524   NS_ENSURE_SUCCESS(rv,rv);
01525   
01526   for (nsDirectoryIterator dir(oldPath, PR_FALSE); dir.Exists(); dir++)
01527   {
01528     nsFileSpec fileOrDirName = dir.Spec();    //set first file or dir to a nsFileSpec
01529 
01530     if (fileOrDirName.IsDirectory())
01531       continue;
01532 
01533     nsCAutoString fileOrDirNameStr(fileOrDirName.GetLeafName());
01534     if (!nsCStringEndsWith(fileOrDirNameStr, pattern))
01535       continue;
01536 
01537 
01538     AddFileCopyToList(&fileOrDirName, &newPath, "");
01539   }  
01540   
01541   return NS_OK;
01542 }
01543 
01544 nsresult nsDogbertProfileMigrator::AddFileCopyToList(nsFileSpec * aOldPath, nsFileSpec * aNewPath, const char * newName)
01545 {
01546   // convert to nsIFile
01547   nsCOMPtr<nsILocalFile> oldPathFile;
01548   nsCOMPtr<nsILocalFile> newPathFile;
01549 
01550   NS_FileSpecToIFile(aOldPath, getter_AddRefs(oldPathFile));
01551   NS_FileSpecToIFile(aNewPath, getter_AddRefs(newPathFile));
01552 
01553   fileTransactionEntry* fileEntry = new fileTransactionEntry;
01554   fileEntry->srcFile = do_QueryInterface(oldPathFile);
01555   fileEntry->destFile = do_QueryInterface(newPathFile);
01556   fileEntry->newName = NS_ConvertUTF8toUCS2(newName);
01557   mFileCopyTransactions->AppendElement((void*) fileEntry);
01558 
01559   return NS_OK;
01560 }
01561 
01562 nsresult nsDogbertProfileMigrator::DoTheCopy(nsIFileSpec * oldPath, nsIFileSpec * newPath, PRBool readSubdirs)
01563 {
01564   return DoTheCopyAndRename(oldPath, newPath, readSubdirs, PR_FALSE, "", "");
01565 }
01566 
01567 nsresult nsDogbertProfileMigrator::DoTheCopy(nsIFileSpec * oldPath, nsIFileSpec * newPath, const char *fileOrDirName, PRBool isDirectory)
01568 {
01569   nsresult rv;
01570 
01571   if (isDirectory)
01572   {
01573     nsCOMPtr<nsIFileSpec> oldSubPath;
01574 
01575     NS_NewFileSpec(getter_AddRefs(oldSubPath));
01576     oldSubPath->FromFileSpec(oldPath);
01577     rv = oldSubPath->AppendRelativeUnixPath(fileOrDirName);
01578     if (NS_FAILED(rv)) return rv;
01579     PRBool exist;
01580     rv = oldSubPath->Exists(&exist);
01581     if (NS_FAILED(rv)) return rv;
01582     if (!exist)
01583     {
01584       rv = oldSubPath->CreateDir();
01585       if (NS_FAILED(rv)) return rv;
01586     }
01587 
01588     nsCOMPtr<nsIFileSpec> newSubPath;
01589 
01590     NS_NewFileSpec(getter_AddRefs(newSubPath));
01591     newSubPath->FromFileSpec(newPath);
01592     rv = newSubPath->AppendRelativeUnixPath(fileOrDirName);
01593     if (NS_FAILED(rv)) return rv;
01594     rv = newSubPath->Exists(&exist);
01595     if (NS_FAILED(rv)) return rv;
01596     if (!exist)
01597     {
01598       rv = newSubPath->CreateDir();
01599       if (NS_FAILED(rv)) return rv;
01600     }
01601 
01602     DoTheCopy(oldSubPath, newSubPath, PR_TRUE);
01603   }
01604   else
01605   {
01606     nsCOMPtr<nsIFileSpec> file;
01607     NS_NewFileSpec(getter_AddRefs(file));
01608     file->FromFileSpec(oldPath);
01609     rv = file->AppendRelativeUnixPath(fileOrDirName);
01610     if( NS_FAILED(rv) ) return rv;
01611     PRBool exist;
01612     rv = file->Exists(&exist);
01613     if( NS_FAILED(rv) ) return rv;
01614     if( exist) {
01615       // convert back to nsFileSpec
01616       nsFileSpec oldPath;
01617       nsFileSpec newPathSpec;
01618 
01619       file->GetFileSpec(&oldPath);
01620       newPath->GetFileSpec(&newPathSpec);
01621       AddFileCopyToList(&oldPath, &newPathSpec, "");
01622     }
01623   }
01624 
01625   return rv;
01626 }
01627 
01628 
01629 /*----------------------------------------------------------------------------
01630  * DoSpecialUpdates updates is a routine that does some miscellaneous updates 
01631  * like renaming certain files, etc.
01632  *--------------------------------------------------------------------------*/
01633 nsresult nsDogbertProfileMigrator::DoSpecialUpdates(nsIFileSpec  * profilePath)
01634 {
01635   nsresult rv;
01636   PRInt32 serverType;
01637   nsFileSpec fs;
01638 
01639   rv = profilePath->GetFileSpec(&fs);
01640   if (NS_FAILED(rv)) return rv;
01641   
01642   fs += PREF_FILE_NAME_IN_5x;
01643   
01644   nsOutputFileStream fsStream(fs, (PR_WRONLY | PR_CREATE_FILE | PR_APPEND));
01645   
01646   if (!fsStream.is_open())
01647   {
01648     return NS_ERROR_FAILURE;
01649   }
01650 
01651   /* Need to add a string to the top of the prefs.js file to prevent it
01652    * from being loaded as a standard javascript file which would be a
01653    * security hole.
01654    */
01655   fsStream << PREF_FILE_HEADER_STRING << nsEndl ;
01656   fsStream.close();
01657     
01658   /* Create the new mail directory from the setting in prefs.js or a default */
01659   rv = mPrefs->GetIntPref(PREF_MAIL_SERVER_TYPE, &serverType);
01660   if (NS_FAILED(rv)) return rv; 
01661   if (serverType == POP_4X_MAIL_TYPE) {
01662        rv = RenameAndMove4xPopFilterFile(profilePath);
01663        if (NS_FAILED(rv)) return rv; 
01664 
01665        rv = RenameAndMove4xPopStateFile(profilePath);
01666        if (NS_FAILED(rv)) return rv; 
01667   }
01668 #ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x 
01669   else if (serverType == IMAP_4X_MAIL_TYPE) {
01670        rv = RenameAndMove4xImapFilterFiles(profilePath);
01671        if (NS_FAILED(rv)) return rv;
01672   }
01673 #endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
01674 
01675   return rv;
01676 }
01677 
01678 nsresult nsDogbertProfileMigrator::RenameAndMove4xPopFilterFile(nsIFileSpec * profilePath)
01679 {
01680   return RenameAndMove4xPopFile(profilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x, POP_MAIL_FILTER_FILE_NAME_IN_5x);
01681 }
01682 
01683 nsresult nsDogbertProfileMigrator::RenameAndMove4xPopStateFile(nsIFileSpec * profilePath)
01684 {
01685 #ifdef POPSTATE_FILE_IN_4x
01686   return RenameAndMove4xPopFile(profilePath, POPSTATE_FILE_IN_4x, POPSTATE_FILE_IN_5x);
01687 #else 
01688   // on windows, popstate.dat was in Users<profile>\MAIL\popstate.dat
01689   // which is the right place, unlike linux and mac.
01690   // so, when we migrate Users<profile>\Mail to Users50<profile>\Mail<hostname>
01691   // it just works
01692   return NS_OK;
01693 #endif /* POPSTATE_FILE_IN_4x */
01694 }
01695 
01696 nsresult nsDogbertProfileMigrator::RenameAndMove4xPopFile(nsIFileSpec * profilePath, const char *fileNameIn4x, const char *fileNameIn5x)
01697 {
01698   nsFileSpec file;
01699   nsresult rv = profilePath->GetFileSpec(&file);
01700   if (NS_FAILED(rv)) return rv;
01701   
01702   // we assume the 4.x pop files live at <profile>/<fileNameIn4x>
01703   file += fileNameIn4x;
01704 
01705   // figure out where the 4.x pop mail directory got copied to
01706   char *popServerName = nsnull;
01707   nsFileSpec migratedPopDirectory;
01708   rv = profilePath->GetFileSpec(&migratedPopDirectory);
01709   migratedPopDirectory += NEW_MAIL_DIR_NAME;
01710   mPrefs->CopyCharPref(PREF_NETWORK_HOSTS_POP_SERVER, &popServerName);
01711   migratedPopDirectory += popServerName;
01712   PR_FREEIF(popServerName);
01713 
01714   // copy the 4.x file from <profile>/<fileNameIn4x> to the <profile>/Mail/<hostname>/<fileNameIn4x>
01715   rv = file.CopyToDir(migratedPopDirectory);
01716   NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy pop file");
01717   
01718   // XXX todo, delete the old file
01719   // we are leaving it behind
01720   
01721   // make migratedPopDirectory point the the copied filter file,
01722   // <profile>/Mail/<hostname>/<fileNameIn4x>
01723   migratedPopDirectory += fileNameIn4x;
01724 
01725   // rename <profile>/Mail/<hostname>/<fileNameIn4x>to <profile>/Mail/<hostname>/<fileNameIn5x>, if necessary
01726   if (PL_strcmp(fileNameIn4x,fileNameIn5x)) {
01727          migratedPopDirectory.Rename(fileNameIn5x);
01728   }
01729 
01730   return NS_OK;
01731 }
01732 
01733 
01734 #ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
01735 #define BUFFER_LEN   128
01736 nsresult nsDogbertProfileMigrator::RenameAndMove4xImapFilterFile(nsIFileSpec * profilePath, const char *hostname)
01737 {
01738   nsresult rv = NS_OK;
01739   char imapFilterFileName[BUFFER_LEN];
01740 
01741   // the 4.x imap filter file lives in "<profile>/<hostname> Rules"
01742   nsFileSpec file;
01743   rv = profilePath->GetFileSpec(&file);
01744   if (NS_FAILED(rv)) return rv;
01745   
01746   PR_snprintf(imapFilterFileName, BUFFER_LEN, IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x, hostname);
01747   file += imapFilterFileName;
01748 
01749   // if that file didn't exist, because they didn't use filters for that server, return now
01750   if (!file.Exists()) return NS_OK;
01751 
01752   // figure out where the 4.x pop mail directory got copied to
01753   nsFileSpec migratedImapDirectory;
01754   rv = profilePath->GetFileSpec(&migratedImapDirectory);
01755   migratedImapDirectory += NEW_IMAPMAIL_DIR_NAME;
01756   migratedImapDirectory += hostname;
01757 
01758   // copy the 4.x file from "<profile>/<hostname> Rules" to <profile>/ImapMail/<hostname>/
01759   rv = file.CopyToDir(migratedImapDirectory);
01760   NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy imap file");
01761 
01762   // make migratedPopDirectory point the the copied filter file,
01763   // "<profile>/ImapMail/<hostname>/<hostname> Rules"
01764   migratedImapDirectory += imapFilterFileName;
01765 
01766   // rename "<profile>/ImapMail/<hostname>/<hostname> Rules" to  "<profile>/ImapMail/<hostname>/rules.dat"
01767   migratedImapDirectory.Rename(IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
01768 
01769   return NS_OK;         
01770 }
01771 
01772 nsresult nsDogbertProfileMigrator::RenameAndMove4xImapFilterFiles(nsIFileSpec * profilePath)
01773 {
01774   nsresult rv;
01775   char *hostList=nsnull;
01776 
01777   rv = mPrefs->CopyCharPref(PREF_4X_NETWORK_HOSTS_IMAP_SERVER, &hostList);
01778   if (NS_FAILED(rv)) return rv;
01779 
01780   if (!hostList || !*hostList) return NS_OK; 
01781 
01782   char *token = nsnull;
01783   char *rest = hostList;
01784   nsCAutoString str;
01785 
01786   token = nsCRT::strtok(rest, ",", &rest);
01787   while (token && *token) {
01788     str = token;
01789     str.StripWhitespace();
01790 
01791     if (!str.IsEmpty()) {
01792       // str is the hostname
01793       rv = RenameAndMove4xImapFilterFile(profilePath,str.get());
01794       if  (NS_FAILED(rv)) {
01795         // failed to migrate.  bail.
01796         return rv;
01797       }
01798       str = "";
01799     }
01800     token = nsCRT::strtok(rest, ",", &rest);
01801   }
01802   PR_FREEIF(hostList);
01803   return NS_OK;    
01804 }
01805 #endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
01806 
01807 nsresult
01808 nsDogbertProfileMigrator::Rename4xFileAfterMigration(nsIFileSpec * profilePath, const char *oldFileName, const char *newFileName)
01809 {
01810   nsresult rv = NS_OK;
01811   // if they are the same, don't bother to rename the file.
01812   if (PL_strcmp(oldFileName, newFileName) == 0) {
01813     return rv;
01814   }
01815                
01816   nsFileSpec file;
01817   rv = profilePath->GetFileSpec(&file);
01818   if (NS_FAILED(rv)) return rv;
01819   
01820   file += oldFileName;
01821   
01822   // make sure it exists before you try to rename it
01823   if (file.Exists()) {
01824     file.Rename(newFileName);
01825   }
01826   return rv;
01827 }
01828 
01829 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
01830 nsresult nsDogbertProfileMigrator::GetPremigratedFilePref(const char *pref_name, nsIFileSpec **path)
01831 {
01832   nsresult rv;
01833   if (!pref_name) return NS_ERROR_FAILURE;
01834   char premigration_pref[MAX_PREF_LEN];
01835   PR_snprintf(premigration_pref,MAX_PREF_LEN,"%s%s",PREMIGRATION_PREFIX,pref_name);
01836   rv = mPrefs->GetFilePref((const char *)premigration_pref, path);
01837   return rv;
01838 }
01839 
01840 #endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
01841 
01842 nsresult nsDogbertProfileMigrator::DetermineOldPath(nsIFileSpec *profilePath, const char *oldPathName, const char *oldPathEntityName, nsIFileSpec *oldPath)
01843 {
01844        nsresult rv;
01845 
01846        /* set oldLocalFile to profilePath.  need to convert nsIFileSpec->nsILocalFile */
01847        nsCOMPtr<nsILocalFile> oldLocalFile;
01848        nsFileSpec pathSpec;
01849        profilePath->GetFileSpec(&pathSpec);
01850        rv = NS_FileSpecToIFile(&pathSpec, getter_AddRefs(oldLocalFile));
01851        if (NS_FAILED(rv)) return rv;
01852        
01853        /* get the string bundle, and get the appropriate localized string out of it */
01854        nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(kStringBundleServiceCID, &rv);
01855        if (NS_FAILED(rv)) return rv;
01856 
01857   nsCOMPtr<nsIStringBundle> bundle;
01858   rv = bundleService->CreateBundle(MIGRATION_PROPERTIES_URL, getter_AddRefs(bundle));
01859        if (NS_FAILED(rv)) return rv;
01860 
01861        nsXPIDLString localizedDirName;
01862        nsAutoString entityName;
01863        entityName.AssignWithConversion(oldPathEntityName);
01864        rv = bundle->GetStringFromName(entityName.get(), getter_Copies(localizedDirName));
01865        if (NS_FAILED(rv)) return rv;
01866 
01867        rv = oldLocalFile->AppendRelativePath(localizedDirName);
01868        if (NS_FAILED(rv)) return rv;
01869 
01870        PRBool exists = PR_FALSE;
01871        rv = oldLocalFile->Exists(&exists);
01872        if (!exists) {
01873               /* if the localized name doesn't exist, use the english name */
01874               rv = oldPath->FromFileSpec(profilePath);
01875               if (NS_FAILED(rv)) return rv;
01876               
01877               rv = oldPath->AppendRelativeUnixPath(oldPathName);
01878               if (NS_FAILED(rv)) return rv;
01879               
01880               return NS_OK;
01881        }
01882 
01883        /* at this point, the folder with the localized name exists, so use it */
01884        nsCAutoString persistentDescriptor;
01885        rv = oldLocalFile->GetPersistentDescriptor(persistentDescriptor);
01886        if (NS_FAILED(rv)) return rv;
01887        rv = oldPath->SetPersistentDescriptorString(persistentDescriptor.get());
01888        if (NS_FAILED(rv)) return rv;
01889 
01890        return NS_OK;
01891 }
01892 
01893 nsresult nsDogbertProfileMigrator::ConvertPersistentStringToFileSpec(const char *str, nsIFileSpec *path)
01894 {
01895        nsresult rv;
01896        if (!str || !path) return NS_ERROR_NULL_POINTER;
01897        
01898        rv = path->SetPersistentDescriptorString(str);
01899        return rv;
01900 }
01901 
01902 /*---------------------------------------------------------------------------------
01903  * GetSizes reads the 4.x files in the profile tree and accumulates their sizes
01904  *--------------------------------------------------------------------------------*/
01905 
01906 nsresult nsDogbertProfileMigrator::GetSizes(nsFileSpec inputPath, PRBool readSubdirs, PRUint32 *sizeTotal)
01907 {
01908   char* folderName;
01909   nsCAutoString fileOrDirNameStr;
01910 
01911   for (nsDirectoryIterator dir(inputPath, PR_FALSE); dir.Exists(); dir++)
01912   {
01913     nsFileSpec fileOrDirName = dir.Spec();
01914     folderName = fileOrDirName.GetLeafName();
01915     fileOrDirNameStr.Assign(folderName);
01916     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 */
01917       continue;
01918     else
01919     {
01920       if (fileOrDirName.IsDirectory())
01921       {
01922         if(readSubdirs)
01923         {
01924           GetSizes(fileOrDirName, PR_TRUE, sizeTotal); /* re-enter the GetSizes function */
01925         }
01926         else
01927           continue;
01928       }
01929       else
01930         *sizeTotal += fileOrDirName.GetFileSize();
01931     }
01932   }
01933 
01934   return NS_OK;
01935 }
01936 
01937 /*---------------------------------------------------------------------------------
01938  * GetDirFromPref gets a directory based on a preference set in the 4.x
01939  * preferences file, adds a 5 and resets the preference.
01940  *
01941  * INPUT: 
01942  *         oldProfilePath - the path to the old 4.x profile directory.  
01943  *                          currently only used by UNIX
01944  *
01945  *         newProfilePath - the path to the 5.0 profile directory
01946  *                          currently only used by UNIX
01947  *
01948  *         newDirName     - the leaf name of the directory in the 5.0 world that corresponds to
01949  *                          this pref.  Examples:  "Mail", "ImapMail", "News".
01950  *                          only used on UNIX.
01951  *
01952  *         pref - the pref in the "dot" format (e.g. mail.directory)
01953  *
01954  * OUTPUT: newPath - The old path with a 5 added (on mac and windows)
01955  *                   the newProfilePath + "/" + newDirName (on UNIX)
01956  *         oldPath - The old path from the pref (if any)
01957  *
01958  *
01959  * RETURNS: NS_OK if the pref was successfully pulled from the prefs file
01960  *
01961  *--------------------------------------------------------------------------------*/
01962 nsresult
01963 nsDogbertProfileMigrator::GetDirFromPref(nsIFileSpec * oldProfilePath, nsIFileSpec * newProfilePath, const char *newDirName, const char* pref, nsIFileSpec* newPath, nsIFileSpec* oldPath)
01964 {
01965   nsresult rv;
01966   
01967   if (!oldProfilePath || !newProfilePath || !newDirName || !pref || !newPath || !oldPath) return NS_ERROR_NULL_POINTER;
01968   
01969   nsCOMPtr <nsIFileSpec> oldPrefPath;
01970   nsXPIDLCString oldPrefPathStr;
01971   rv = mPrefs->CopyCharPref(pref,getter_Copies(oldPrefPathStr));
01972   if (NS_FAILED(rv)) return rv;
01973   
01974   // the default on the mac was "".  doing GetFileXPref on that would return
01975   // the current working directory, like viewer_debug.  yikes!
01976   if (oldPrefPathStr.IsEmpty()) {
01977        rv = NS_ERROR_FAILURE;
01978   }
01979   if (NS_FAILED(rv)) return rv;
01980   
01981   nsCOMPtr <nsILocalFile> oldPrefPathFile;
01982   rv = mPrefs->GetFileXPref(pref, getter_AddRefs(oldPrefPathFile));
01983   if (NS_FAILED(rv)) return rv;
01984   
01985   // convert nsILocalFile to nsIFileSpec
01986   rv = oldPrefPathFile->GetNativePath(oldPrefPathStr);
01987   if (NS_FAILED(rv)) return rv;
01988 
01989   rv = NS_NewFileSpec(getter_AddRefs(oldPrefPath));
01990   if (NS_FAILED(rv)) return rv;
01991   
01992   rv = oldPrefPath->SetNativePath(oldPrefPathStr);
01993   if (NS_FAILED(rv)) return rv;
01994 
01995   // oldPath will also needs the conversion from nsILocalFile
01996   // this is nasty, eventually we'll switch entirely over to nsILocalFile
01997   rv = oldPath->SetNativePath(oldPrefPathStr);
01998   if (NS_FAILED(rv)) return rv;
01999 
02000   
02001 #ifdef XP_UNIX
02002        // what if they don't want to go to <profile>/<newDirName>?
02003        // what if unix users want "mail.directory" + "5" (like "~/ns_imap5")
02004        // or "mail.imap.root_dir" + "5" (like "~/nsmail5")?
02005        // should we let them?  no.  let's migrate them to
02006        // <profile>/Mail and <profile>/ImapMail
02007        // let's make all three platforms the same.
02008        if (PR_TRUE) {
02009 #else
02010        nsCOMPtr <nsIFileSpec> oldPrefPathParent;
02011        rv = oldPrefPath->GetParent(getter_AddRefs(oldPrefPathParent));
02012        if (NS_FAILED(rv)) return rv;
02013 
02014        // if the pref pointed to the default directory
02015        // treat it as if the pref wasn't set
02016        // this way it will get migrated as the user expects
02017        PRBool pathsMatch;
02018        rv = oldProfilePath->Equals(oldPrefPathParent, &pathsMatch);
02019        if (NS_SUCCEEDED(rv) && pathsMatch) {
02020 #endif /* XP_UNIX */
02021               rv = newPath->FromFileSpec(newProfilePath);
02022               if (NS_FAILED(rv)) return rv;
02023        }
02024        else {
02025               nsXPIDLCString leafname;
02026               rv = newPath->FromFileSpec(oldPath);
02027               if (NS_FAILED(rv)) return rv;
02028               rv = newPath->GetLeafName(getter_Copies(leafname));
02029               if (NS_FAILED(rv)) return rv;
02030               nsCString newleafname((const char *)leafname);
02031               newleafname += NEW_DIR_SUFFIX;
02032               rv = newPath->SetLeafName(newleafname.get());
02033               if (NS_FAILED(rv)) return rv;
02034        }
02035 
02036   rv = SetPremigratedFilePref(pref, oldPath);
02037   if (NS_FAILED(rv)) return rv;
02038   
02039 #ifdef XP_UNIX
02040   /* on UNIX, we kept the newsrc files in "news.directory", (which was usually ~)
02041    * and the summary files in ~/.netscape/xover-cache
02042    * oldPath should point to ~/.netscape/xover-cache, not "news.directory"
02043    * but we want to save the old "news.directory" in "premigration.news.directory"
02044    * later, again for UNIX only, 
02045    * we will copy the .newsrc files (from "news.directory") into the new <profile>/News directory.
02046    * isn't this fun?  
02047    */
02048   if (PL_strcmp(PREF_NEWS_DIRECTORY, pref) == 0) {
02049     rv = oldPath->FromFileSpec(oldProfilePath);
02050     if (NS_FAILED(rv)) return rv;
02051     rv = oldPath->AppendRelativeUnixPath(OLD_NEWS_DIR_NAME);
02052     if (NS_FAILED(rv)) return rv;
02053   }
02054 #endif /* XP_UNIX */
02055   return rv;
02056 }
02057 
02058 nsresult nsDogbertProfileMigrator::SetPremigratedFilePref(const char *pref_name, nsIFileSpec *path)
02059 {
02060        nsresult rv;
02061 
02062        if (!pref_name) return NS_ERROR_FAILURE;
02063 
02064        // save off the old pref, prefixed with "premigration"
02065        // for example, we need the old "mail.directory" pref when
02066        // migrating the copies and folder prefs in nsMsgAccountManager.cpp
02067        //
02068        // note we do this for all platforms.
02069        char premigration_pref[MAX_PREF_LEN];
02070        PR_snprintf(premigration_pref,MAX_PREF_LEN,"%s%s",PREMIGRATION_PREFIX,pref_name);
02071 
02072   // need to convert nsIFileSpec->nsILocalFile
02073   nsFileSpec pathSpec;
02074   path->GetFileSpec(&pathSpec);
02075   
02076   nsCOMPtr<nsILocalFile> pathFile;
02077   rv = NS_FileSpecToIFile(&pathSpec, getter_AddRefs(pathFile));
02078   if (NS_FAILED(rv)) return rv;
02079   
02080   PRBool exists = PR_FALSE;
02081   pathFile->Exists(&exists);
02082   
02083   NS_ASSERTION(exists, "the path does not exist.  see bug #55444");
02084   if (!exists) return NS_OK;
02085   
02086        rv = mPrefs->SetFileXPref((const char *)premigration_pref, pathFile);
02087        return rv;
02088 }
02089 
02090 nsresult nsDogbertProfileMigrator::ComputeSpaceRequirements(PRInt64 DriveArray[MAX_DRIVES], 
02091                                           PRUint32 SpaceReqArray[MAX_DRIVES], 
02092                                           PRInt64 Drive, 
02093                                           PRUint32 SpaceNeeded)
02094 {
02095   int i=0;
02096   PRFloat64 temp;
02097 
02098   while(LL_NE(DriveArray[i],LL_Zero()) && LL_NE(DriveArray[i], Drive) && i < MAX_DRIVES)
02099     i++;
02100 
02101   if (LL_EQ(DriveArray[i], LL_Zero()))
02102   {
02103     DriveArray[i] = Drive;
02104     SpaceReqArray[i] += SpaceNeeded;
02105   }
02106   else if (LL_EQ(DriveArray[i], Drive))
02107     SpaceReqArray[i] += SpaceNeeded;
02108   else
02109     return NS_ERROR_FAILURE;
02110   
02111   LL_L2F(temp, DriveArray[i]);
02112   if (SpaceReqArray[i] > temp)
02113     return NS_ERROR_FAILURE;
02114   
02115   return NS_OK;
02116 }
02117 
02118 static PRBool
02119 nsCStringEndsWith(nsCString& name, const char *ending)
02120 {
02121   if (!ending) return PR_FALSE;
02122 
02123   PRInt32 len = name.Length();
02124   if (len == 0) return PR_FALSE;
02125 
02126   PRInt32 endingLen = PL_strlen(ending);
02127   if (len > endingLen && name.RFind(ending, PR_TRUE) == len - endingLen) {
02128         return PR_TRUE;
02129   }
02130   else {
02131         return PR_FALSE;
02132   }
02133 }
02134 
02135 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
02136 static PRBool
02137 nsCStringStartsWith(nsCString& name, const char *starting)
02138 {
02139        if (!starting) return PR_FALSE;
02140        PRInt32       len = name.Length();
02141        if (len == 0) return PR_FALSE;
02142        
02143        PRInt32 startingLen = PL_strlen(starting);
02144        if (len > startingLen && name.RFind(starting, PR_TRUE) == 0) {
02145               return PR_TRUE;
02146        }
02147        else {
02148               return PR_FALSE;
02149        }
02150 }
02151 #endif
02152 
02154 // nsPrefConverter
02156 
02157 /* 
02158   these are the prefs we know we need to convert to utf8.
02159   we'll also be converting:
02160 
02161   Please make sure that any pref that contains native characters
02162   in it's value is not included in this list as we do not want to 
02163   convert them into UTF-8 format. Prefs are being get and set in a 
02164   unicode format (FileXPref) now and there is no need for 
02165   conversion of those prefs. 
02166 
02167  "ldap_2.server.*.description"
02168  "intl.font*.fixed_font"
02169  "intl.font*.prop_font"
02170  "mail.identity.vcard.*"
02171  */
02172 
02173 static const char *prefsToConvert[] = {
02174       "li.server.ldap.userbase",
02175       "mail.identity.organization",
02176       "mail.identity.username",
02177       nsnull
02178 };
02179 
02180 nsPrefConverter::~nsPrefConverter()
02181 {}
02182 
02183 
02184 nsPrefConverter::nsPrefConverter()
02185 {}
02186 
02187 // Apply a charset conversion from the given charset to UTF-8 for the input C string.
02188 static nsresult ConvertStringToUTF8(const char* aCharset, const char* inString, char** outString)
02189 {
02190   if (nsnull == outString)
02191     return NS_ERROR_NULL_POINTER;
02192 
02193   nsresult rv;
02194   // convert result to unicode
02195   nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(kCharsetConverterManagerCID, &rv);
02196 
02197   if(NS_SUCCEEDED(rv)) {
02198     nsCOMPtr <nsIUnicodeDecoder> decoder; // this may be cached
02199 
02200     rv = ccm->GetUnicodeDecoderRaw(aCharset, getter_AddRefs(decoder));
02201     if(NS_SUCCEEDED(rv) && decoder) {
02202       PRInt32 uniLength = 0;
02203       PRInt32 srcLength = strlen(inString);
02204       rv = decoder->GetMaxLength(inString, srcLength, &uniLength);
02205       if (NS_SUCCEEDED(rv)) {
02206         PRUnichar *unichars = new PRUnichar [uniLength];
02207 
02208         if (nsnull != unichars) {
02209           // convert to unicode
02210           rv = decoder->Convert(inString, &srcLength, unichars, &uniLength);
02211           if (NS_SUCCEEDED(rv)) {
02212             nsAutoString aString;
02213             aString.Assign(unichars, uniLength);
02214             // convert to UTF-8
02215             *outString = ToNewUTF8String(aString);
02216           }
02217           delete [] unichars;
02218         }
02219         else {
02220           rv = NS_ERROR_OUT_OF_MEMORY;
02221         }
02222       }
02223     }    
02224   }
02225 
02226   return rv;
02227 }
02228 
02229 nsresult ConvertPrefToUTF8(const char *prefname, nsIPref *prefs, const char* charSet)
02230 {
02231   nsresult rv;
02232 
02233   if (!prefname || !prefs) return NS_ERROR_FAILURE;  
02234   nsXPIDLCString prefval;
02235 
02236   rv = prefs->CopyCharPref(prefname, getter_Copies(prefval));
02237   if (NS_FAILED(rv)) return rv;
02238 
02239   if (prefval.IsEmpty()) 
02240     return NS_OK;
02241 
02242   nsXPIDLCString outval;
02243   rv = ConvertStringToUTF8(charSet, (const char *)prefval, getter_Copies(outval));
02244   // only set the pref if the conversion worked, and it convert to something non null
02245   if (NS_SUCCEEDED(rv) && (const char *)outval && PL_strlen((const char *)outval)) 
02246     rv = prefs->SetCharPref(prefname, (const char *)outval);
02247   return NS_OK;
02248 }
02249 
02250 static PRBool charEndsWith(const char *str, const char *endStr)
02251 {
02252   PRUint32 endStrLen = PL_strlen(endStr);
02253   PRUint32 strLen = PL_strlen(str);
02254     
02255   if (strLen < endStrLen) return PR_FALSE;
02256 
02257   PRUint32 pos = strLen - endStrLen;
02258   if (PL_strncmp(str + pos, endStr, endStrLen) == 0)
02259     return PR_TRUE;
02260   else 
02261     return PR_FALSE;
02262 }
02263 
02264 static void fontPrefEnumerationFunction(const char *name, void *data)
02265 {
02266   nsCStringArray *arr;
02267   arr = (nsCStringArray *)data;
02268   if (charEndsWith(name,".fixed_font") || charEndsWith(name,".prop_font")) {
02269     nsCString str(name);
02270     arr->AppendCString(str);
02271   }
02272 }
02273 
02274 static void ldapPrefEnumerationFunction(const char *name, void *data)
02275 {
02276   nsCStringArray *arr;
02277   arr = (nsCStringArray *)data;
02278   // we only want to convert "ldap_2.servers.*.description"
02279   if (charEndsWith(name,".description")) {
02280     nsCString str(name);
02281     arr->AppendCString(str);
02282   }
02283 }
02284 
02285 static void vCardPrefEnumerationFunction(const char *name, void *data)
02286 {
02287   nsCStringArray *arr;
02288   arr = (nsCStringArray *)data;
02289 
02290   // the 4.x vCard prefs might need converting
02291   nsCString str(name);
02292   arr->AppendCString(str);
02293 }
02294 
02295 
02296 typedef struct {
02297     nsIPref *prefs;
02298     const char* charSet;
02299 } PrefEnumerationClosure;
02300 
02301 PRBool convertPref(nsCString &aElement, void *aData)
02302 {
02303   PrefEnumerationClosure *closure;
02304   closure = (PrefEnumerationClosure *)aData;
02305 
02306   ConvertPrefToUTF8(aElement.get(), closure->prefs, closure->charSet);
02307   return PR_TRUE;
02308 }
02309 
02310 nsresult nsPrefConverter::ConvertPrefsToUTF8()
02311 {
02312   nsresult rv;
02313 
02314   nsCStringArray prefsToMigrate;
02315   nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID, &rv));
02316 
02317   if(NS_FAILED(rv)) return rv;
02318   if (!prefs) return NS_ERROR_FAILURE;
02319 
02320   nsCAutoString charSet;
02321   rv = GetPlatformCharset(charSet);
02322   
02323   if (NS_FAILED(rv)) return rv;
02324 
02325   for (PRUint32 i = 0; prefsToConvert[i]; i++) {
02326     nsCString prefnameStr( prefsToConvert[i] );
02327     prefsToMigrate.AppendCString(prefnameStr);
02328   }
02329 
02330   prefs->EnumerateChildren("intl.font",fontPrefEnumerationFunction,(void *)(&prefsToMigrate));
02331   prefs->EnumerateChildren("ldap_2.servers",ldapPrefEnumerationFunction,(void *)(&prefsToMigrate));
02332   prefs->EnumerateChildren("mail.identity.vcard",vCardPrefEnumerationFunction,(void *)(&prefsToMigrate));
02333 
02334   PrefEnumerationClosure closure;
02335 
02336   closure.prefs = prefs;
02337   closure.charSet = charSet.get();
02338 
02339   prefsToMigrate.EnumerateForwards((nsCStringArrayEnumFunc)convertPref, (void *)(&closure));
02340 
02341   rv = prefs->SetBoolPref("prefs.converted-to-utf8",PR_TRUE);
02342   return NS_OK;
02343 }
02344 
02345 // A wrapper function to call the interface to get a platform file charset.
02346 nsresult 
02347 nsPrefConverter::GetPlatformCharset(nsCString& aCharset)
02348 {
02349   nsresult rv;
02350 
02351   // we may cache it since the platform charset will not change through application life
02352   nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
02353   if (NS_SUCCEEDED(rv) && platformCharset)
02354    rv = platformCharset->GetCharset(kPlatformCharsetSel_4xPrefsJS, aCharset);
02355   if (NS_FAILED(rv))
02356    aCharset.Assign(NS_LITERAL_CSTRING("ISO-8859-1"));  // use ISO-8859-1 in case of any error
02357  
02358   return rv;
02359 }