Back to index

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