Back to index

lightning-sunbird  0.9+nobinonly
nsProfile.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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.org 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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nscore.h" 
00039 #include "nsProfile.h"
00040 #ifdef MOZ_PROFILELOCKING
00041 #include "nsProfileLock.h"
00042 #endif
00043 #include "nsIPrefService.h"
00044 #include "nsIPrefBranch.h"
00045 
00046 #include "pratom.h"
00047 #include "prmem.h"
00048 #include "plstr.h"
00049 #include "prenv.h"
00050 
00051 #include "nsIFactory.h"
00052 #include "nsIComponentManager.h"
00053 #include "nsIEnumerator.h"
00054 #include "nsXPIDLString.h"
00055 #include "nsEscape.h"
00056 #include "nsIURL.h"
00057 #include "nsNativeCharsetUtils.h"
00058 
00059 #include "prprf.h"
00060 
00061 #include "nsIIOService.h"
00062 #include "nsNetUtil.h"
00063 #include "nsPrefMigration.h"
00064 #include "nsIPrefMigration.h"
00065 #include "nsPrefMigrationCIDs.h"
00066 #include "nsFileStream.h"
00067 #include "nsIPromptService.h"
00068 #include "nsIStreamListener.h"
00069 #include "nsIServiceManager.h"
00070 #include "nsCOMPtr.h"
00071 #include "nsIModule.h"
00072 #include "nsIGenericFactory.h"
00073 #include "nsICookieService.h"
00074 #include "nsICategoryManager.h"
00075 #include "nsXPCOM.h"
00076 #include "nsISupportsPrimitives.h"
00077 #include "nsIDirectoryService.h"
00078 #include "nsDirectoryServiceDefs.h"
00079 #include "nsAppDirectoryServiceDefs.h"
00080 #include "nsIChromeRegistrySea.h"
00081 #include "nsIStringBundle.h"
00082 #include "nsIObserverService.h"
00083 #include "nsHashtable.h"
00084 #include "nsIAtom.h"
00085 #include "nsProfileDirServiceProvider.h"
00086 #include "nsISessionRoaming.h"
00087 
00088 // Interfaces Needed
00089 #include "nsIDocShell.h"
00090 #include "nsIWebBrowserChrome.h"
00091 
00092 #include "nsIScriptGlobalObject.h"
00093 #include "nsIScriptContext.h"
00094 #include "nsIBaseWindow.h"
00095 #include "nsIDialogParamBlock.h"
00096 #include "nsIDOMWindowInternal.h"
00097 #include "nsIWindowWatcher.h"
00098 #include "jsapi.h"
00099 #include "nsIJSContextStack.h"
00100 #include "nsEmbedCID.h"
00101 
00102 #if defined(XP_MAC) || defined(XP_MACOSX)
00103 #define OLD_REGISTRY_FILE_NAME "Netscape Registry"
00104 #elif defined(XP_WIN) || defined(XP_OS2)
00105 #define OLD_REGISTRY_FILE_NAME "nsreg.dat"
00106 #endif
00107 
00108 
00109 // A default profile name, in case automigration 4x profile fails
00110 #define DEFAULT_PROFILE_NAME           (NS_LITERAL_STRING("default").get())
00111 
00112 #define PROFILE_SELECTION_URL          "chrome://communicator/content/profile/profileSelection.xul"
00113 #define PROFILE_SELECTION_CMD_LINE_ARG "-SelectProfile"
00114 #define PROFILE_MANAGER_URL            "chrome://communicator/content/profile/profileSelection.xul?manage=true"
00115 #define PROFILE_MANAGER_CMD_LINE_ARG   "-ProfileManager"
00116 #define PROFILE_WIZARD_URL             "chrome://communicator/content/profile/createProfileWizard.xul"
00117 #define PROFILE_WIZARD_CMD_LINE_ARG    "-ProfileWizard"
00118 #define INSTALLER_CMD_LINE_ARG         "-installer"
00119 #define CREATE_PROFILE_CMD_LINE_ARG    "-CreateProfile"
00120 #define PROFILE_CMD_LINE_ARG "-P"   
00121 #define UILOCALE_CMD_LINE_ARG "-UILocale"   
00122 #define CONTENTLOCALE_CMD_LINE_ARG "-contentLocale"   
00123 
00124 #define PREF_CONFIRM_AUTOMIGRATION     "profile.confirm_automigration"
00125 #define PREF_AUTOMIGRATION             "profile.allow_automigration"
00126 #define PREF_MIGRATE_ALL               "profile.migrate_all"
00127 #define PREF_MIGRATION_BEHAVIOR        "profile.migration_behavior"
00128 #define PREF_MIGRATION_DIRECTORY       "profile.migration_directory"
00129 
00130 #if defined (XP_MAC)
00131 #define CHROME_STYLE nsIWebBrowserChrome::CHROME_WINDOW_BORDERS | nsIWebBrowserChrome::CHROME_WINDOW_CLOSE | nsIWebBrowserChrome::CHROME_CENTER_SCREEN
00132 #else /* the rest */
00133 #define CHROME_STYLE nsIWebBrowserChrome::CHROME_ALL | nsIWebBrowserChrome::CHROME_CENTER_SCREEN
00134 #endif 
00135 
00136 const char* kDefaultOpenWindowParams = "centerscreen,chrome,modal,titlebar";
00137 
00138 const char* kBrandBundleURL = "chrome://branding/locale/brand.properties";
00139 const char* kMigrationBundleURL = "chrome://communicator/locale/profile/migration.properties";
00140 
00141 // we want everyone to have the debugging info to the console for now
00142 // to help track down profile manager problems
00143 // when we ship, we'll turn this off
00144 #undef DEBUG_profile_verbose
00145 #ifdef DEBUG_seth
00146 #define DEBUG_profile_verbose 1
00147 #endif
00148 
00149 
00150 // ProfileAccess varaible (gProfileDataAccess) to access registry operations
00151 // gDataAccessInstCount is used to keep track of instance count to activate
00152 // destructor at the right time (count == 0)
00153 static nsProfileAccess*    gProfileDataAccess = nsnull;
00154 static PRInt32          gInstanceCount = 0;
00155 
00156 // Profile database to remember which profile has been
00157 // created with UILocale and contentLocale on profileManager
00158 static nsHashtable *gLocaleProfiles = nsnull;
00159 static nsProfileDirServiceProvider *gDirServiceProvider = nsnull;
00160 
00161 // IID and CIDs of all the services needed
00162 static NS_DEFINE_CID(kPrefMigrationCID, NS_PREFMIGRATION_CID);
00163 static NS_DEFINE_CID(kPrefConverterCID, NS_PREFCONVERTER_CID);
00164 
00165 #define NS_SESSIONROAMING_CONTRACTID "@mozilla.org/profile/session-roaming;1"
00166 
00167 
00168 /*
00169     Copies the contents of srcDir into destDir.
00170     destDir will be created if it doesn't exist.
00171 */
00172 
00173 static
00174 nsresult RecursiveCopy(nsIFile* srcDir, nsIFile* destDir)
00175 {
00176     nsresult rv;
00177     PRBool isDir;
00178     
00179     rv = srcDir->IsDirectory(&isDir);
00180     if (NS_FAILED(rv)) return rv;
00181        if (!isDir) return NS_ERROR_INVALID_ARG;
00182 
00183     PRBool exists;
00184     rv = destDir->Exists(&exists);
00185        if (NS_SUCCEEDED(rv) && !exists)
00186               rv = destDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
00187        if (NS_FAILED(rv)) return rv;
00188 
00189     PRBool hasMore = PR_FALSE;
00190     nsCOMPtr<nsISimpleEnumerator> dirIterator;
00191     rv = srcDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
00192     if (NS_FAILED(rv)) return rv;
00193     
00194     rv = dirIterator->HasMoreElements(&hasMore);
00195     if (NS_FAILED(rv)) return rv;
00196     
00197     nsCOMPtr<nsIFile> dirEntry;
00198     
00199        while (hasMore)
00200        {
00201               rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
00202               if (NS_SUCCEEDED(rv))
00203               {
00204                   rv = dirEntry->IsDirectory(&isDir);
00205                   if (NS_SUCCEEDED(rv))
00206                   {
00207                       if (isDir)
00208                       {
00209                           nsCOMPtr<nsIFile> destClone;
00210                           rv = destDir->Clone(getter_AddRefs(destClone));
00211                           if (NS_SUCCEEDED(rv))
00212                           {
00213                               nsCOMPtr<nsILocalFile> newChild(do_QueryInterface(destClone));
00214                               nsCAutoString leafName;
00215                               dirEntry->GetNativeLeafName(leafName);
00216                               newChild->AppendRelativeNativePath(leafName);
00217                               rv = RecursiveCopy(dirEntry, newChild);
00218                           }
00219                       }
00220                       else
00221                           rv = dirEntry->CopyToNative(destDir, EmptyCString());
00222                   }
00223               
00224               }
00225         rv = dirIterator->HasMoreElements(&hasMore);
00226         if (NS_FAILED(rv)) return rv;
00227        }
00228 
00229        return rv;
00230 }
00231 
00232 
00233 /*
00234  * Constructor/Destructor
00235  */
00236 nsProfile::nsProfile()
00237 {
00238     mStartingUp = PR_FALSE;
00239     mAutomigrate = PR_FALSE;
00240     mOutofDiskSpace = PR_FALSE;
00241     mDiskSpaceErrorQuitCalled = PR_FALSE;
00242     mCurrentProfileAvailable = PR_FALSE;
00243 
00244     mIsUILocaleSpecified = PR_FALSE;
00245     mIsContentLocaleSpecified = PR_FALSE;
00246     
00247     mShutdownProfileToreDownNetwork = PR_FALSE;
00248     
00249     mProfileChangeVetoed = PR_FALSE;
00250     mProfileChangeFailed = PR_FALSE;
00251 }
00252 
00253 nsProfile::~nsProfile() 
00254 {
00255 #if defined(DEBUG_profile_verbose)
00256     printf("~nsProfile \n");
00257 #endif
00258 
00259    if (--gInstanceCount == 0) {
00260         
00261       delete gProfileDataAccess;
00262       delete gLocaleProfiles;
00263       NS_IF_RELEASE(gDirServiceProvider);
00264     }
00265 }
00266 
00267 nsresult
00268 nsProfile::Init()
00269 {
00270     nsresult rv = NS_OK;
00271     
00272     if (gInstanceCount++ == 0) {
00273         gProfileDataAccess = new nsProfileAccess;
00274         if (!gProfileDataAccess)
00275             return NS_ERROR_OUT_OF_MEMORY;
00276         gLocaleProfiles = new nsHashtable();
00277         if (!gLocaleProfiles)
00278             return NS_ERROR_OUT_OF_MEMORY;
00279 
00280         rv = NS_NewProfileDirServiceProvider(PR_FALSE, &gDirServiceProvider);
00281         if (NS_SUCCEEDED(rv))
00282             rv = gDirServiceProvider->Register();
00283     }
00284     return rv;
00285 }
00286 
00287 /*
00288  * nsISupports Implementation
00289  */
00290 NS_IMPL_THREADSAFE_ADDREF(nsProfile)
00291 NS_IMPL_THREADSAFE_RELEASE(nsProfile)
00292 
00293 NS_INTERFACE_MAP_BEGIN(nsProfile)
00294     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProfile)
00295     NS_INTERFACE_MAP_ENTRY(nsIProfile)
00296     NS_INTERFACE_MAP_ENTRY(nsIProfileInternal)
00297     NS_INTERFACE_MAP_ENTRY(nsIProfileChangeStatus)
00298 NS_INTERFACE_MAP_END
00299 
00300 /*
00301  * nsIProfile Implementation
00302  */
00303 
00304 NS_IMETHODIMP
00305 nsProfile::GetAutomigrate(PRBool *aAutomigrate)
00306 {
00307     NS_ENSURE_ARG_POINTER(aAutomigrate);
00308 
00309     *aAutomigrate = mAutomigrate;
00310     return NS_OK;
00311 }
00312 
00313 NS_IMETHODIMP
00314 nsProfile::SetAutomigrate(PRBool aAutomigrate)
00315 {
00316     mAutomigrate = aAutomigrate;
00317     return NS_OK;
00318 }
00319 
00320 NS_IMETHODIMP
00321 nsProfile::StartupWithArgs(nsICmdLineService *cmdLineArgs, PRBool canInteract)
00322 {
00323     nsresult rv;
00324 
00325     struct ScopeFlag
00326     {
00327         ScopeFlag(PRBool *flagPtr) : mFlagPtr(flagPtr)
00328         { *mFlagPtr = PR_TRUE; }
00329 
00330         ~ScopeFlag()
00331         { *mFlagPtr = PR_FALSE; }
00332 
00333         PRBool *mFlagPtr;
00334     };
00335 
00336     // initializations for profile manager
00337     PRBool profileDirSet = PR_FALSE;
00338     nsCString profileURLStr("");
00339 
00340 #ifdef DEBUG_profile_verbose
00341     printf("Profile Manager : Profile Wizard and Manager activites : Begin\n");
00342 #endif
00343 
00344     ScopeFlag startupFlag(&mStartingUp);
00345 
00346     if (cmdLineArgs)
00347         rv = ProcessArgs(cmdLineArgs, canInteract, &profileDirSet, profileURLStr);
00348 
00349     // This boolean is set only when an automigrated user runs out of disk space
00350     // and chooses to cancel further operations from the dialogs presented...
00351     if (mDiskSpaceErrorQuitCalled)
00352         return NS_ERROR_FAILURE;
00353 
00354     if (!profileDirSet) {
00355         rv = LoadDefaultProfileDir(profileURLStr, canInteract);
00356 
00357         if (NS_FAILED(rv)) return rv;
00358     }
00359 
00360     // Ensure that by this point we have a current profile.
00361     // If -CreateProfile was used, we won't, and we're supposed to exit.
00362     nsXPIDLString currentProfileStr;
00363     rv = GetCurrentProfile(getter_Copies(currentProfileStr));
00364     if (NS_FAILED(rv) || (*(const PRUnichar*)currentProfileStr == 0)) {
00365         return NS_ERROR_ABORT;
00366     }
00367 
00368 
00369     // check UILocale is specified on profileManager, otherwise,
00370     // when -UILocale option is specified, install the UILocale
00371 
00372     // -UILocale or -contentLocale is not specified
00373     if (mIsUILocaleSpecified == PR_FALSE && mIsContentLocaleSpecified == PR_FALSE) {
00374         return NS_OK;
00375     }
00376 
00377     nsCOMPtr<nsIFile> profileDir;
00378 
00379     rv = GetCurrentProfileDir(getter_AddRefs(profileDir));
00380     if (NS_FAILED(rv)) return rv;
00381 
00382     nsCAutoString pathBuf;
00383     rv = profileDir->GetNativePath(pathBuf);
00384     if (NS_FAILED(rv)) return rv;
00385 
00386     // -UILocale or -contentLocale has been specified, but
00387     // user has selected UILocale and contentLocale for this profile
00388     // on profileManager
00389     // We should not set here
00390     nsCStringKey key(pathBuf);
00391     if (NS_PTR_TO_INT32(gLocaleProfiles->Get(&key)) == PR_TRUE) {
00392 #ifdef DEBUG_profile_verbose
00393         printf(" already set UILocale and contentLocale: %s\n", pathBuf.get());
00394         printf(" will not install locale\n");
00395 #endif
00396         return NS_OK;
00397     }
00398     gLocaleProfiles->Remove(&key);
00399 
00400     nsCOMPtr<nsIChromeRegistrySea> chromeRegistry =
00401         do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
00402     if (NS_FAILED(rv)) return rv;
00403 
00404     // Install to the profile
00405     nsCAutoString fileStr;
00406     rv = NS_GetURLSpecFromFile(profileDir, fileStr);
00407     if (NS_FAILED(rv)) return rv;
00408 
00409     // NEED TO FIX: when current UILocale and contentLocale are same with specified locales,
00410     // we shouldn't install them again here. But packageRegistry->GetSelectedLocale() doesn't
00411     // work here properly. It always returns global and global-region of default not current
00412     // profile
00413     if (!mUILocaleName.IsEmpty()) {
00414 #ifdef DEBUG_profile_verbose
00415         printf(" install new UILocaleName: %s\n", mUILocaleName.get());
00416 #endif
00417         rv = chromeRegistry->SelectLocaleForProfile(mUILocaleName,
00418                                           NS_ConvertUTF8toUCS2(fileStr).get());
00419         if (NS_FAILED(rv)) return rv;
00420     }
00421 
00422     if (!mContentLocaleName.IsEmpty()) {
00423 #ifdef DEBUG_profile_verbose
00424         printf(" install new mContentLocaleName: %s\n", mContentLocaleName.get());
00425 #endif
00426         rv = chromeRegistry->SelectLocaleForProfile(mContentLocaleName,
00427                                           NS_ConvertUTF8toUCS2(fileStr).get());
00428         if (NS_FAILED(rv)) return rv;
00429     }
00430 
00431 #ifdef DEBUG_profile_verbose
00432     printf("Profile Manager : Profile Wizard and Manager activites : End\n");
00433 #endif
00434 
00435     return NS_OK;
00436 }
00437 
00438 NS_IMETHODIMP
00439 nsProfile::GetIsStartingUp(PRBool *aIsStartingUp)
00440 {
00441     NS_ENSURE_ARG_POINTER(aIsStartingUp);
00442     *aIsStartingUp = mStartingUp;
00443     return NS_OK;
00444 }
00445 
00446 nsresult
00447 nsProfile::LoadDefaultProfileDir(nsCString & profileURLStr, PRBool canInteract)
00448 {
00449     nsresult rv;
00450     nsCOMPtr<nsIURI> profileURL;
00451     PRInt32 numProfiles=0;
00452   
00453     GetProfileCount(&numProfiles);
00454 
00455     if (profileURLStr.IsEmpty())
00456     {
00457         nsCOMPtr<nsIPrefBranch> prefBranch;
00458         nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00459         if (NS_FAILED(rv)) return rv;
00460         rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
00461         if (NS_FAILED(rv)) return rv;
00462     
00463         // If this flag is TRUE, it makes the multiple profile case
00464         // just like the single profile case - the profile will be
00465         // set to that returned by GetCurrentProfile(). It will prevent
00466         // the profile selection dialog from being shown when we have
00467         // multiple profiles.
00468         
00469         PRBool startWithLastUsedProfile = PR_FALSE;
00470 
00471         // But first, make sure this app supports this.
00472         PRBool cantAutoSelect;
00473         rv = prefBranch->GetBoolPref("profile.manage_only_at_launch", &cantAutoSelect);
00474         if (NS_SUCCEEDED(rv) && !cantAutoSelect)
00475           GetStartWithLastUsedProfile(&startWithLastUsedProfile);
00476         
00477         // This means that there was no command-line argument to force
00478         // profile UI to come up. But we need the UI anyway if there
00479         // are no profiles yet, or if there is more than one.
00480         if (numProfiles == 0)
00481         {
00482             rv = CreateDefaultProfile();
00483             if (NS_FAILED(rv)) return rv;
00484             // Will get set in call to SetCurrentProfile() below
00485         }
00486         else if (numProfiles == 1 || startWithLastUsedProfile)
00487         {
00488             // If we get here and the 1 profile is the current profile,
00489             // which can happen with QuickLaunch, there's no need to do
00490             // any futher work.
00491             if (mCurrentProfileAvailable)
00492                return NS_OK;
00493 
00494             // Make sure the profile dir exists. If not, we need the UI
00495             nsCOMPtr<nsIFile> curProfileDir;
00496             PRBool exists = PR_FALSE;
00497             
00498             rv = GetCurrentProfileDir(getter_AddRefs(curProfileDir));
00499             if (NS_SUCCEEDED(rv))
00500                 rv = curProfileDir->Exists(&exists);
00501             if (NS_FAILED(rv) || !exists)
00502                 profileURLStr = PROFILE_MANAGER_URL; 
00503             if (exists)
00504             {
00505 #ifdef MOZ_PROFILELOCKING
00506                 // If the profile is locked, we need the UI
00507                 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(curProfileDir));
00508                 nsProfileLock tempLock;
00509                 rv = tempLock.Lock(localFile, nsnull);
00510                 if (NS_FAILED(rv))
00511                     profileURLStr = PROFILE_MANAGER_URL;
00512 #endif
00513             }
00514         }
00515         else
00516             profileURLStr = PROFILE_SELECTION_URL;
00517     }
00518 
00519     if (!profileURLStr.IsEmpty())
00520     {
00521         if (!canInteract) return NS_ERROR_PROFILE_REQUIRES_INTERACTION;
00522 
00523         nsCOMPtr<nsIWindowWatcher> windowWatcher(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
00524         if (NS_FAILED(rv)) return rv;
00525 
00526         nsCOMPtr<nsIDialogParamBlock> ioParamBlock(do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &rv));
00527         if (NS_FAILED(rv)) return rv;
00528 
00529         // String0  -> mode
00530         // Int0    <-  result code (1 == OK, 0 == Cancel)
00531 
00532         ioParamBlock->SetNumberStrings(1);
00533         ioParamBlock->SetString(0, NS_LITERAL_STRING("startup").get());
00534 
00535         nsCOMPtr<nsIDOMWindow> newWindow;
00536         rv = windowWatcher->OpenWindow(nsnull,
00537                                        profileURLStr.get(),
00538                                        "_blank",
00539                                        kDefaultOpenWindowParams,
00540                                        ioParamBlock,
00541                                        getter_AddRefs(newWindow));
00542         if (NS_FAILED(rv)) return rv;
00543         PRInt32 dialogConfirmed;
00544         ioParamBlock->GetInt(0, &dialogConfirmed);
00545         if (dialogConfirmed == 0) return NS_ERROR_ABORT;
00546     }
00547 
00548     nsXPIDLString currentProfileStr;    
00549     rv = GetCurrentProfile(getter_Copies(currentProfileStr));
00550     if (NS_FAILED(rv)) return rv;
00551 
00552     // if at this point we have a current profile but it is not set, set it
00553     if (!mCurrentProfileAvailable) {
00554         rv = SetCurrentProfile(currentProfileStr);
00555         if (NS_FAILED(rv)) return rv;
00556     }
00557 
00558     return NS_OK;
00559 }
00560 
00561 nsresult
00562 nsProfile::ConfirmAutoMigration(PRBool canInteract, PRBool *confirmed)
00563 {
00564     NS_ENSURE_ARG_POINTER(confirmed);
00565     nsCOMPtr<nsIPrefBranch> prefBranch;
00566     *confirmed = PR_FALSE;
00567     nsresult rv;
00568     
00569     // First check PREF_CONFIRM_AUTOMIGRATION.
00570     // If FALSE, we go ahead and migrate without asking.
00571     PRBool confirmAutomigration = PR_TRUE;
00572     nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00573     if (NS_FAILED(rv)) return rv;
00574     rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
00575     if (NS_FAILED(rv)) return rv;
00576 
00577     (void)prefBranch->GetBoolPref(PREF_CONFIRM_AUTOMIGRATION, &confirmAutomigration);
00578     if (!confirmAutomigration) {
00579         *confirmed = PR_TRUE;
00580         return NS_OK;
00581     }
00582     
00583     // If allowed, put up a confirm dialog and ask the user
00584     if (!canInteract)
00585         return NS_ERROR_PROFILE_REQUIRES_INTERACTION;
00586 
00587     nsCOMPtr<nsIStringBundleService> stringBundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
00588     if (NS_FAILED(rv)) return rv;
00589 
00590     nsCOMPtr<nsIStringBundle> migrationBundle, brandBundle;
00591     rv = stringBundleService->CreateBundle(kMigrationBundleURL, getter_AddRefs(migrationBundle));
00592     if (NS_FAILED(rv)) return rv;
00593     rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle));
00594     if (NS_FAILED(rv)) return rv;
00595     
00596     nsXPIDLString brandName;
00597     rv = brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(), getter_Copies(brandName));
00598     if (NS_FAILED(rv)) return rv;
00599 
00600     nsXPIDLString msgString, dialogTitle, button0Title, button1Title;
00601     const PRUnichar *formatStrings[] = { brandName.get(), brandName.get() };
00602     rv = migrationBundle->FormatStringFromName(NS_LITERAL_STRING("confirmMigration").get(),
00603                                                  formatStrings, 2, getter_Copies(msgString));
00604     if (NS_FAILED(rv)) return rv;
00605     
00606     rv = migrationBundle->GetStringFromName(NS_LITERAL_STRING("dialogTitle").get(), getter_Copies(dialogTitle));
00607     if (NS_FAILED(rv)) return rv;
00608     rv = migrationBundle->GetStringFromName(NS_LITERAL_STRING("migrate").get(), getter_Copies(button0Title));
00609     if (NS_FAILED(rv)) return rv;
00610     rv = migrationBundle->GetStringFromName(NS_LITERAL_STRING("manage").get(), getter_Copies(button1Title));
00611     if (NS_FAILED(rv)) return rv;
00612     
00613     nsCOMPtr<nsIPromptService> promptService(do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv));
00614     if (NS_FAILED(rv)) return rv;
00615     PRInt32 buttonPressed;
00616     rv = promptService->ConfirmEx(nsnull, dialogTitle.get(), msgString.get(),
00617                                   (nsIPromptService::BUTTON_POS_0 * nsIPromptService::BUTTON_TITLE_IS_STRING) +
00618                                   (nsIPromptService::BUTTON_POS_1 * nsIPromptService::BUTTON_TITLE_IS_STRING),
00619                                   button0Title, button1Title, nsnull,
00620                                   nsnull, nsnull, &buttonPressed);
00621     if (NS_FAILED(rv)) return rv;
00622     *confirmed = (buttonPressed == 0);
00623     return NS_OK;
00624 }
00625 
00626 nsresult 
00627 nsProfile::AutoMigrate()
00628 {
00629     nsresult rv = NS_OK;
00630     // automatically migrate the one 4.x profile
00631     rv = MigrateAllProfiles();
00632 
00633     // Create a default profile if automigration failed for reasons
00634     // other than out of disk space case...
00635     if (NS_FAILED(rv) && !mOutofDiskSpace) 
00636     {
00637 #ifdef DEBUG_profile
00638         printf("AutoMigration failed. Let's create a default 5.0 profile.\n");
00639 #endif
00640         
00641         rv = CreateDefaultProfile();
00642         if (NS_FAILED(rv)) return rv;
00643     }   
00644 
00645     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
00646     gProfileDataAccess->UpdateRegistry(nsnull);
00647 
00648     return rv;
00649 }
00650 
00651 nsresult
00652 nsProfile::ProcessArgs(nsICmdLineService *cmdLineArgs,
00653                        PRBool canInteract,
00654                        PRBool* profileDirSet,
00655                        nsCString & profileURLStr)
00656 {
00657     NS_ASSERTION(cmdLineArgs, "Invalid cmdLineArgs");   
00658     NS_ASSERTION(profileDirSet, "Invalid profileDirSet");   
00659 
00660     nsresult rv;
00661     nsXPIDLCString cmdResult;
00662     nsCOMPtr<nsILocalFile> currProfileDir;
00663 
00664        // keep track of if the user passed us any profile related command line args
00665        // if they did, we won't force migration
00666        PRBool foundProfileCommandArg = PR_FALSE;
00667 
00668 #ifdef DEBUG_profile_verbose
00669     printf("Profile Manager : Command Line Options : Begin\n");
00670 #endif
00671  
00672     // check for command line arguments for profile manager
00673     // -UILocale command
00674     rv = cmdLineArgs->GetCmdLineValue(UILOCALE_CMD_LINE_ARG, getter_Copies(cmdResult));
00675     if (NS_SUCCEEDED(rv))
00676     {
00677         if (cmdResult) {
00678            mIsUILocaleSpecified = PR_TRUE;
00679             mUILocaleName = cmdResult;
00680         }
00681     }
00682 
00683     // -contentLocale command
00684     rv = cmdLineArgs->GetCmdLineValue(CONTENTLOCALE_CMD_LINE_ARG, getter_Copies(cmdResult));
00685     if (NS_SUCCEEDED(rv))
00686     {
00687         if (cmdResult) {
00688             mIsContentLocaleSpecified = PR_TRUE;
00689             mContentLocaleName = cmdResult;
00690         }
00691     }
00692 
00693     // -P command line option works this way:
00694     // apprunner -P profilename 
00695     // runs the app using the profile <profilename> 
00696     // remembers profile for next time
00697     rv = cmdLineArgs->GetCmdLineValue(PROFILE_CMD_LINE_ARG, getter_Copies(cmdResult));
00698     if (NS_SUCCEEDED(rv))
00699     {
00700         if (cmdResult) {
00701             foundProfileCommandArg = PR_TRUE;
00702             nsAutoString currProfileName; 
00703             rv = NS_CopyNativeToUnicode(cmdResult, currProfileName); 
00704             NS_ASSERTION(NS_SUCCEEDED(rv), "failed to convert ProfileName to unicode");
00705  
00706 #ifdef DEBUG_profile
00707             printf("ProfileName : %s\n", (const char*)cmdResult);
00708 #endif /* DEBUG_profile */
00709             PRBool exists;
00710             rv = ProfileExists(currProfileName.get(), &exists);
00711             if (NS_FAILED(rv)) return rv;            
00712             
00713             if (!exists) {
00714                 PRInt32 num5xProfiles = 0;
00715                 PRInt32 num4xProfiles = 0;
00716 
00717                 GetProfileCount(&num5xProfiles);
00718                 Get4xProfileCount(&num4xProfiles);
00719 
00720                 if (num5xProfiles == 0 && num4xProfiles == 0) {
00721                     profileURLStr = PROFILE_WIZARD_URL;
00722                 }
00723                 else if (num5xProfiles > 0) {
00724                     profileURLStr = PROFILE_SELECTION_URL;
00725                 }
00726                 else if (num4xProfiles > 0) {
00727                     profileURLStr = PROFILE_MANAGER_URL;
00728                 }
00729                 *profileDirSet = PR_FALSE;
00730             }
00731             else {
00732                 rv = SetCurrentProfile(currProfileName.get());
00733                 if (NS_SUCCEEDED(rv))
00734                     *profileDirSet = PR_TRUE;
00735             }
00736         }
00737     }
00738 
00739     // -CreateProfile command line option works this way:
00740     // apprunner -CreateProfile profilename 
00741     // creates a new profile named <profilename> and sets the directory to your CWD 
00742     // runs app using that profile 
00743     // remembers profile for next time 
00744     //                         - OR -
00745     // apprunner -CreateProfile "profilename profiledir" 
00746     // creates a new profile named <profilename> and sets the directory to <profiledir> 
00747     // runs app using that profile 
00748     // remembers profile for next time
00749 
00750     rv = cmdLineArgs->GetCmdLineValue(CREATE_PROFILE_CMD_LINE_ARG, getter_Copies(cmdResult));
00751     if (NS_SUCCEEDED(rv))
00752     {
00753         if (cmdResult) {
00754 
00755 #ifdef DEBUG_profile_verbose
00756             printf("profileName & profileDir are: %s\n", (const char*)cmdResult);
00757 #endif
00758             foundProfileCommandArg = PR_TRUE;
00759             nsAutoString currProfileName; 
00760  
00761             char *tmpStr;
00762             rv = NS_CopyNativeToUnicode(
00763                  nsDependentCString(nsCRT::strtok(cmdResult.BeginWriting(), " ", &tmpStr)),
00764                                     currProfileName);
00765             NS_ASSERTION(NS_SUCCEEDED(rv), "failed to convert ProfileName to unicode");
00766 
00767             char *currProfileDirString = nsCRT::strtok(tmpStr, " ", &tmpStr); 
00768             if (currProfileDirString && *currProfileDirString) {
00769                 rv = NS_NewNativeLocalFile(nsDependentCString(currProfileDirString), 
00770                      PR_TRUE, getter_AddRefs(currProfileDir));
00771                 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
00772             }
00773             else {
00774                 // No directory name provided. Place it in
00775                 // NS_APP_USER_PROFILES_ROOT_DIR
00776                 nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
00777                 if (NS_FAILED(rv)) return rv;
00778                 rv = directoryService->Get(NS_APP_USER_PROFILES_ROOT_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(currProfileDir));
00779                 if (NS_FAILED(rv)) return rv;
00780             }
00781 
00782             nsAutoString currProfilePath;
00783             currProfileDir->GetPath(currProfilePath);
00784             rv = CreateNewProfile(currProfileName.get(), currProfilePath.get(), nsnull, PR_TRUE);
00785             if (NS_SUCCEEDED(rv)) {
00786                 *profileDirSet = PR_TRUE;
00787                 mCurrentProfileAvailable = PR_TRUE;
00788                 gProfileDataAccess->SetCurrentProfile(currProfileName.get());
00789 
00790                 // Load new profile prefs for the sake of tinderbox scripts
00791                 // which assume prefs.js exists after -CreateProfile.
00792                 nsCOMPtr<nsIFile> newProfileDir;
00793                 GetProfileDir(currProfileName.get(), getter_AddRefs(newProfileDir));
00794                 if (newProfileDir) {
00795                   nsCOMPtr<nsIFile> localDir;
00796                   GetLocalProfileDir(currProfileName.get(), getter_AddRefs(localDir));
00797                   gDirServiceProvider->SetProfileDir(newProfileDir, localDir);
00798                 }
00799                 rv = LoadNewProfilePrefs();
00800                 gProfileDataAccess->mProfileDataChanged = PR_TRUE;
00801                 gProfileDataAccess->UpdateRegistry(nsnull);
00802             }
00803             rv = ForgetCurrentProfile();
00804             if (NS_FAILED(rv)) return rv;
00805         }
00806     }
00807 
00808     // Start Profile Manager
00809     rv = cmdLineArgs->GetCmdLineValue(PROFILE_MANAGER_CMD_LINE_ARG, getter_Copies(cmdResult));
00810     if (NS_SUCCEEDED(rv))
00811     {        
00812         if (cmdResult) {
00813                      foundProfileCommandArg = PR_TRUE;
00814             profileURLStr = PROFILE_MANAGER_URL;
00815         }
00816     }
00817     
00818     // Start Profile Selection
00819     rv = cmdLineArgs->GetCmdLineValue(PROFILE_SELECTION_CMD_LINE_ARG, getter_Copies(cmdResult));
00820     if (NS_SUCCEEDED(rv))
00821     {        
00822         if (cmdResult) {
00823                      foundProfileCommandArg = PR_TRUE;
00824             profileURLStr = PROFILE_SELECTION_URL;
00825         }
00826     }
00827     
00828     
00829     // Start Profile Wizard
00830     rv = cmdLineArgs->GetCmdLineValue(PROFILE_WIZARD_CMD_LINE_ARG, getter_Copies(cmdResult));
00831     if (NS_SUCCEEDED(rv))
00832     {        
00833         if (cmdResult) {
00834                      foundProfileCommandArg = PR_TRUE;
00835             profileURLStr = PROFILE_WIZARD_URL;
00836         }
00837     }
00838 
00839        PRBool forceMigration = PR_FALSE;
00840        if (!foundProfileCommandArg) {
00841               rv = gProfileDataAccess->DetermineForceMigration(&forceMigration);
00842               NS_ASSERTION(NS_SUCCEEDED(rv),"failed to determine if we should force migration");
00843        }
00844 
00845     nsCOMPtr<nsIPrefBranch> prefBranch;
00846    
00847     // First check PREF_AUTOMIGRATION. 
00848     PRBool allowAutoMigration = PR_TRUE;
00849     nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00850     if (NS_FAILED(rv)) return rv;
00851     rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
00852     if (NS_FAILED(rv)) return rv;
00853 
00854     (void)prefBranch->GetBoolPref(PREF_AUTOMIGRATION, &allowAutoMigration);
00855 
00856     // Start Migaration activity
00857     rv = cmdLineArgs->GetCmdLineValue(INSTALLER_CMD_LINE_ARG, getter_Copies(cmdResult));
00858     if (allowAutoMigration && (NS_SUCCEEDED(rv) || forceMigration))
00859     {        
00860         if (cmdResult || forceMigration) {
00861         PRBool migrateAll = PR_FALSE;
00862         (void)prefBranch->GetBoolPref(PREF_MIGRATE_ALL, &migrateAll);
00863 
00864             rv = MigrateProfileInfo();
00865             if (NS_FAILED(rv)) return rv;
00866 
00867             PRInt32 num4xProfiles = 0;
00868             rv = Get4xProfileCount(&num4xProfiles);
00869             if (NS_FAILED(rv)) return rv;
00870             
00871             PRInt32 numProfiles = 0;
00872             GetProfileCount(&numProfiles);
00873             if (num4xProfiles == 0 && numProfiles == 0) {
00874                 // Let us create a default 5.0 profile
00875                 CreateDefaultProfile();
00876                 if (NS_FAILED(rv)) return rv;
00877             }
00878             else if (num4xProfiles == 0 && numProfiles == 1) {
00879                 profileURLStr = "";
00880             }
00881             else if ((num4xProfiles == 1 || migrateAll) && numProfiles == 0) {
00882                 PRBool confirmed = PR_FALSE;
00883                 if (NS_SUCCEEDED(ConfirmAutoMigration(canInteract, &confirmed)) && confirmed)
00884                     AutoMigrate();
00885                 else
00886                     profileURLStr = PROFILE_MANAGER_URL;
00887             }
00888             else if (numProfiles > 1)
00889             {
00890                 profileURLStr = PROFILE_SELECTION_URL;
00891             }
00892             else {
00893                 // show the profile manager
00894                 profileURLStr = PROFILE_MANAGER_URL;
00895             }
00896         }
00897     }
00898 
00899 #ifdef DEBUG_profile_verbose
00900     printf("Profile Manager : Command Line Options : End\n");
00901 #endif
00902 
00903     return NS_OK;
00904 }
00905 
00906 
00907 /*
00908  * Getters
00909  */
00910 
00911 // Gets the profiles directory for a given profile
00912 // Sets the given profile to be a current profile
00913 NS_IMETHODIMP nsProfile::GetProfileDir(const PRUnichar *profileName, nsIFile **profileDir)
00914 {
00915     NS_ENSURE_ARG(profileName);   
00916     NS_ENSURE_ARG_POINTER(profileDir);
00917     *profileDir = nsnull;
00918 
00919     nsresult rv = NS_OK;
00920 
00921 #if defined(DEBUG_profile_verbose)
00922     printf("ProfileManager : GetProfileDir\n");
00923 #endif
00924 
00925     ProfileStruct    *aProfile;
00926 
00927     rv = gProfileDataAccess->GetValue(profileName, &aProfile);
00928     if (NS_FAILED(rv)) return rv;
00929 
00930        if (aProfile == nsnull)
00931               return NS_ERROR_FAILURE;
00932 
00933     nsCOMPtr<nsILocalFile>aProfileDir;
00934     rv = aProfile->GetResolvedProfileDir(getter_AddRefs(aProfileDir));
00935     if (NS_SUCCEEDED(rv) && aProfileDir)
00936     {
00937 #ifdef XP_MAC
00938         PRBool exists;
00939         rv = aProfileDir->Exists(&exists);
00940         if (NS_FAILED(rv)) return rv;
00941         if (exists) {
00942             PRBool inTrash;
00943             nsCOMPtr<nsIFile> trashFolder;
00944                             
00945             rv = NS_GetSpecialDirectory(NS_MAC_TRASH_DIR, getter_AddRefs(trashFolder));
00946             if (NS_FAILED(rv)) return rv;
00947             rv = trashFolder->Contains(aProfileDir, PR_TRUE, &inTrash);
00948             if (NS_FAILED(rv)) return rv;
00949             if (inTrash) {
00950                 aProfileDir = nsnull;
00951                 rv = NS_ERROR_FILE_NOT_FOUND;
00952             }  
00953         }
00954 #endif
00955         *profileDir = aProfileDir;
00956         NS_IF_ADDREF(*profileDir);
00957     }    
00958        delete aProfile;
00959     return rv;
00960 }
00961 
00962 NS_IMETHODIMP nsProfile::GetProfilePath(const PRUnichar *profileName, PRUnichar **_retval)
00963 {
00964     NS_ENSURE_ARG(profileName);
00965     NS_ENSURE_ARG_POINTER(_retval);
00966     *_retval = nsnull;
00967     
00968     nsCOMPtr<nsIFile> profileDir;
00969     nsresult rv = GetProfileDir(profileName, getter_AddRefs(profileDir));
00970     if (NS_FAILED(rv)) return rv;
00971     
00972     PRBool isSalted;    
00973     nsCOMPtr<nsIFile> prettyDir(profileDir);
00974     rv = IsProfileDirSalted(profileDir, &isSalted);
00975     if (NS_SUCCEEDED(rv) && isSalted) {
00976         nsCOMPtr<nsIFile> parentDir;
00977         rv = profileDir->GetParent(getter_AddRefs(parentDir));
00978         if (NS_SUCCEEDED(rv))
00979             prettyDir = parentDir;
00980     }
00981     nsAutoString path;
00982     rv = prettyDir->GetPath(path);
00983     if (NS_FAILED(rv)) return rv;
00984 
00985     *_retval = ToNewUnicode(path);
00986     return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00987 }
00988 
00989 NS_IMETHODIMP nsProfile::GetOriginalProfileDir(const PRUnichar *profileName, nsILocalFile **originalDir)
00990 {
00991     NS_ENSURE_ARG(profileName);
00992     NS_ENSURE_ARG_POINTER(originalDir);
00993     *originalDir = nsnull;
00994 
00995     Update4xProfileInfo();
00996     return gProfileDataAccess->GetOriginalProfileDir(profileName, originalDir);
00997 }
00998 
00999 NS_IMETHODIMP nsProfile::GetProfileLastModTime(const PRUnichar *profileName, PRInt64 *_retval)
01000 {
01001     NS_ENSURE_ARG(profileName);
01002     NS_ENSURE_ARG_POINTER(_retval);
01003     nsresult rv;
01004     
01005     // First, see if we can get the lastModTime from the registry.
01006     // We only started putting it there from mozilla1.0.1
01007     // The mod time will be zero if it has not been set.
01008     ProfileStruct *profileInfo = nsnull;
01009     rv = gProfileDataAccess->GetValue(profileName, &profileInfo);
01010     if (NS_SUCCEEDED(rv)) {
01011         PRInt64 lastModTime = profileInfo->lastModTime;
01012         delete profileInfo;
01013         if (!LL_IS_ZERO(lastModTime)) {
01014             *_retval = lastModTime;
01015             return NS_OK;
01016         }
01017     }
01018 
01019     // Since we couldn't get a valid mod time from the registry,
01020     // check the date of prefs.js. Since August, 2000 it is always
01021     // written out on quitting the application.
01022     nsCOMPtr<nsIFile> profileDir;
01023     rv = GetProfileDir(profileName, getter_AddRefs(profileDir));
01024     if (NS_FAILED(rv))
01025         return rv;
01026     rv = profileDir->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
01027     if (NS_FAILED(rv))
01028         return rv;
01029     return profileDir->GetLastModifiedTime(_retval);
01030 }
01031 
01032 NS_IMETHODIMP nsProfile::GetDefaultProfileParentDir(nsIFile **aDefaultProfileParentDir)
01033 {
01034     NS_ENSURE_ARG_POINTER(aDefaultProfileParentDir);
01035 
01036     nsresult rv;
01037     
01038     nsCOMPtr<nsIFile> aDir;
01039     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(aDir));
01040     NS_ENSURE_SUCCESS(rv, rv);
01041 
01042     *aDefaultProfileParentDir = aDir;
01043     NS_ADDREF(*aDefaultProfileParentDir);
01044 
01045     return NS_OK;
01046 }
01047 
01048 // Gets the number of profiles
01049 // Location: Common/Profiles
01050 NS_IMETHODIMP nsProfile::GetProfileCount(PRInt32 *numProfiles)
01051 {
01052     NS_ENSURE_ARG_POINTER(numProfiles);
01053 
01054     *numProfiles = 0;
01055 
01056     gProfileDataAccess->GetNumProfiles(numProfiles);
01057     return NS_OK;
01058 }
01059 
01060 
01061 // If only a single profile exists
01062 // return the name of the single profile.
01063 // Otherwise it return the name of the first valid profile.
01064 NS_IMETHODIMP nsProfile::GetFirstProfile(PRUnichar **profileName)
01065 {
01066     NS_ENSURE_ARG_POINTER(profileName);
01067 
01068     gProfileDataAccess->GetFirstProfile(profileName);
01069     gProfileDataAccess->SetCurrentProfile(*profileName);
01070 
01071     return NS_OK;
01072 }
01073 
01074 NS_IMETHODIMP nsProfile::GetStartWithLastUsedProfile(PRBool *aStartWithLastUsedProfile)
01075 {
01076     NS_ENSURE_ARG_POINTER(aStartWithLastUsedProfile);
01077     return gProfileDataAccess->GetStartWithLastUsedProfile(aStartWithLastUsedProfile);
01078 }
01079 
01080 NS_IMETHODIMP nsProfile::SetStartWithLastUsedProfile(PRBool aStartWithLastUsedProfile)
01081 {
01082     return gProfileDataAccess->SetStartWithLastUsedProfile(aStartWithLastUsedProfile);
01083 }
01084 
01085 // Returns the name of the current profile i.e., the last used profile
01086 NS_IMETHODIMP
01087 nsProfile::GetCurrentProfile(PRUnichar **profileName)
01088 {
01089     NS_ENSURE_ARG_POINTER(profileName);
01090     *profileName = nsnull;
01091 
01092     if (!mCurrentProfileName.IsEmpty()) 
01093       *profileName = ToNewUnicode(mCurrentProfileName);
01094     else 
01095       gProfileDataAccess->GetCurrentProfile(profileName);
01096     return (*profileName == nsnull) ? NS_ERROR_FAILURE : NS_OK;
01097 }
01098 
01099 
01100 NS_IMETHODIMP
01101 nsProfile::SetCurrentProfile(const PRUnichar * aCurrentProfile)
01102 {
01103     NS_ENSURE_ARG(aCurrentProfile);
01104     
01105     nsresult rv;
01106     nsCOMPtr<nsIFile> profileDir;
01107     PRBool exists;
01108 
01109     // Ensure that the profile exists and its directory too.
01110     rv = GetProfileDir(aCurrentProfile, getter_AddRefs(profileDir));
01111     if (NS_FAILED(rv)) return rv;
01112     rv = profileDir->Exists(&exists);
01113     if (NS_FAILED(rv)) return rv;
01114     if (!exists) return NS_ERROR_FILE_NOT_FOUND;
01115 
01116     PRBool isSwitch;
01117 
01118     if (mCurrentProfileAvailable)
01119     {
01120         nsXPIDLString currProfileName;
01121         rv = GetCurrentProfile(getter_Copies(currProfileName));
01122         if (NS_FAILED(rv)) return rv;
01123         if (nsCRT::strcmp(aCurrentProfile, currProfileName.get()) == 0)
01124             return NS_OK;
01125         else
01126             isSwitch = PR_TRUE;
01127     }
01128     else
01129         isSwitch = PR_FALSE;
01130 #ifdef MOZ_PROFILELOCKING    
01131     nsProfileLock localLock;
01132     nsCOMPtr<nsILocalFile> localProfileDir(do_QueryInterface(profileDir, &rv));
01133     if (NS_FAILED(rv)) return rv;
01134     rv = localLock.Lock(localProfileDir, nsnull);
01135     if (NS_FAILED(rv))
01136     {
01137         NS_ERROR("Could not get profile directory lock.");
01138         return rv;
01139     }
01140 #endif
01141     nsCOMPtr<nsIObserverService> observerService = 
01142              do_GetService("@mozilla.org/observer-service;1", &rv);
01143     NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
01144     
01145     nsISupports *subject = (nsISupports *)((nsIProfile *)this);
01146     NS_NAMED_LITERAL_STRING(switchString, "switch");
01147     NS_NAMED_LITERAL_STRING(startupString, "startup");
01148     const nsAFlatString& context = isSwitch ? switchString : startupString;
01149     
01150     if (isSwitch)
01151     {
01152         // Phase 1: See if anybody objects to the profile being changed.
01153         mProfileChangeVetoed = PR_FALSE;        
01154         observerService->NotifyObservers(subject, "profile-approve-change", context.get());
01155         if (mProfileChangeVetoed)
01156             return NS_OK;
01157 
01158         // Phase 2a: Send the network teardown notification
01159         observerService->NotifyObservers(subject, "profile-change-net-teardown", context.get());
01160         mShutdownProfileToreDownNetwork = PR_TRUE;
01161 
01162         // Phase 2b: Send the "teardown" notification
01163         observerService->NotifyObservers(subject, "profile-change-teardown", context.get());
01164         if (mProfileChangeVetoed)
01165         {
01166             // Notify we will not proceed with changing the profile
01167             observerService->NotifyObservers(subject, "profile-change-teardown-veto", context.get());
01168 
01169             // Bring network back online and return
01170             observerService->NotifyObservers(subject, "profile-change-net-restore", context.get());
01171             return NS_OK;
01172         }
01173         
01174         // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
01175         // resources which are about to go away in "profile-before-change" are destroyed first.
01176         nsCOMPtr<nsIThreadJSContextStack> stack =
01177           do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01178         if (NS_SUCCEEDED(rv))
01179         {
01180           JSContext *cx = nsnull;
01181           stack->GetSafeJSContext(&cx);
01182           if (cx)
01183             ::JS_GC(cx);
01184         }
01185         
01186         // Phase 3: Notify observers of a profile change
01187         observerService->NotifyObservers(subject, "profile-before-change", context.get());        
01188         if (mProfileChangeFailed)
01189           return NS_ERROR_ABORT;
01190         
01191         UpdateCurrentProfileModTime(PR_FALSE);        
01192     }
01193 
01194 #ifdef MOZ_PROFILELOCKING    
01195     // Do the profile switch
01196     localLock.Unlock(); // gDirServiceProvider will get and hold its own lock
01197 #endif
01198     nsCOMPtr<nsIFile> localDir;
01199     GetLocalProfileDir(aCurrentProfile, getter_AddRefs(localDir));
01200     gDirServiceProvider->SetProfileDir(profileDir, localDir);
01201     mCurrentProfileName.Assign(aCurrentProfile);    
01202     gProfileDataAccess->SetCurrentProfile(aCurrentProfile);
01203     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
01204     gProfileDataAccess->UpdateRegistry(nsnull);
01205             
01206     if (NS_FAILED(rv)) return rv;
01207     mCurrentProfileAvailable = PR_TRUE;
01208     
01209     if (!isSwitch)
01210     {
01211         // Ensure that the prefs service exists so it can respond to
01212         // the notifications we're about to send around. It needs to.
01213         nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01214         NS_ASSERTION(NS_SUCCEEDED(rv), "Could not get prefs service");
01215     }
01216 
01217     if (mShutdownProfileToreDownNetwork)
01218     {
01219         // Bring network back online
01220         observerService->NotifyObservers(subject, "profile-change-net-restore", context.get());
01221         mShutdownProfileToreDownNetwork = PR_FALSE;
01222         if (mProfileChangeFailed)
01223           return NS_ERROR_ABORT;
01224     }
01225 
01226     // Roaming download
01227     // Tolerate errors. Maybe the roaming extension isn't installed.
01228     nsCOMPtr <nsISessionRoaming> roam =
01229       do_GetService(NS_SESSIONROAMING_CONTRACTID, &rv);
01230     if (NS_SUCCEEDED(rv))
01231       roam->BeginSession();
01232 
01233     // Phase 4: Notify observers that the profile has changed - Here they respond to new profile
01234     observerService->NotifyObservers(subject, "profile-do-change", context.get());
01235     if (mProfileChangeFailed)
01236       return NS_ERROR_ABORT;
01237 
01238     // Phase 5: Now observers can respond to something another observer did in phase 4
01239     observerService->NotifyObservers(subject, "profile-after-change", context.get());
01240     if (mProfileChangeFailed)
01241       return NS_ERROR_ABORT;
01242 
01243     // Now that a profile is established, set the profile defaults dir for the locale of this profile
01244     rv = DefineLocaleDefaultsDir();
01245     NS_ASSERTION(NS_SUCCEEDED(rv), "nsProfile::DefineLocaleDefaultsDir failed");
01246 
01247     // Phase 6: One last notification after the new profile is established
01248     observerService->NotifyObservers(subject, "profile-initial-state", context.get());
01249     if (mProfileChangeFailed)
01250       return NS_ERROR_ABORT;
01251 
01252     nsCOMPtr<nsICategoryManager> catman =
01253              do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
01254 
01255     if(NS_SUCCEEDED(rv) && catman)
01256     {
01257         nsCOMPtr<nsISimpleEnumerator> enumItem;
01258         rv = catman->EnumerateCategory(NS_PROFILE_STARTUP_CATEGORY, getter_AddRefs(enumItem));
01259         if(NS_SUCCEEDED(rv) && enumItem)
01260         {
01261            while (PR_TRUE)
01262            {
01263                nsCOMPtr<nsISupportsCString> contractid;
01264 
01265                rv = enumItem->GetNext(getter_AddRefs(contractid));
01266                if (NS_FAILED(rv) || !contractid) break;
01267 
01268                nsCAutoString contractidString;
01269                contractid->GetData(contractidString);
01270         
01271                nsCOMPtr <nsIProfileStartupListener> listener = do_GetService(contractidString.get(), &rv);
01272         
01273                if (listener)
01274                    listener->OnProfileStartup(aCurrentProfile);
01275            }
01276         }
01277     }
01278 
01279     nsCOMPtr<nsIPrefBranch> prefBranch;
01280   
01281     nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01282     if (NS_FAILED(rv)) return rv;
01283     rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
01284     if (NS_FAILED(rv)) return rv;
01285 
01286     PRBool prefs_converted = PR_FALSE;
01287     (void)prefBranch->GetBoolPref("prefs.converted-to-utf8", &prefs_converted);
01288 
01289     if (!prefs_converted)
01290     {
01291         nsCOMPtr <nsIPrefConverter> pPrefConverter = do_GetService(kPrefConverterCID, &rv);
01292         if (!pPrefConverter) return NS_ERROR_FAILURE;
01293         rv = pPrefConverter->ConvertPrefsToUTF8();
01294         if (NS_FAILED(rv)) return rv;
01295     }
01296     
01297     return NS_OK;
01298 }
01299 
01300 
01301 // Returns the name of the current profile directory
01302 NS_IMETHODIMP nsProfile::GetCurrentProfileDir(nsIFile **profileDir)
01303 {
01304     NS_ENSURE_ARG_POINTER(profileDir);
01305     nsresult rv;
01306 
01307     nsXPIDLString profileName;
01308     rv = GetCurrentProfile(getter_Copies(profileName));
01309     if (NS_FAILED(rv)) return rv;
01310 
01311     rv = GetProfileDir(profileName, profileDir);
01312     if (NS_FAILED(rv)) return rv;
01313 
01314     return NS_OK;
01315 }
01316 
01317 // Performs a "logout" by shutting down the current profile
01318 NS_IMETHODIMP nsProfile::ShutDownCurrentProfile(PRUint32 shutDownType)
01319 {
01320     nsresult rv;
01321     
01322     // if shutDownType is not a well know value, skip the notifications
01323     // see DoOnShutdown() in nsAppRunner.cpp for where we use this behaviour to our benefit
01324     if (shutDownType == SHUTDOWN_PERSIST || shutDownType == SHUTDOWN_CLEANSE) {
01325       nsCOMPtr<nsIObserverService> observerService = 
01326         do_GetService("@mozilla.org/observer-service;1", &rv);
01327       NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
01328       
01329       nsISupports *subject = (nsISupports *)((nsIProfile *)this);
01330       
01331       NS_NAMED_LITERAL_STRING(cleanseString, "shutdown-cleanse");
01332       NS_NAMED_LITERAL_STRING(persistString, "shutdown-persist");
01333       const nsAFlatString& context = (shutDownType == SHUTDOWN_CLEANSE) ? cleanseString : persistString;
01334       
01335       // Phase 1: See if anybody objects to the profile being changed.
01336       mProfileChangeVetoed = PR_FALSE;        
01337       observerService->NotifyObservers(subject, "profile-approve-change", context.get());
01338       if (mProfileChangeVetoed)
01339         return NS_OK;
01340       
01341       // Phase 2a: Send the network teardown notification
01342       observerService->NotifyObservers(subject, "profile-change-net-teardown", context.get());
01343       mShutdownProfileToreDownNetwork = PR_TRUE;
01344 
01345       // Phase 2b: Send the "teardown" notification
01346       observerService->NotifyObservers(subject, "profile-change-teardown", context.get());
01347 
01348       // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
01349       // resources which are about to go away in "profile-before-change" are destroyed first.
01350       nsCOMPtr<nsIThreadJSContextStack> stack =
01351         do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01352       if (NS_SUCCEEDED(rv))
01353       {
01354         JSContext *cx = nsnull;
01355         stack->GetSafeJSContext(&cx);
01356         if (cx)
01357           ::JS_GC(cx);
01358       }
01359       
01360       // Phase 3: Notify observers of a profile change
01361       observerService->NotifyObservers(subject, "profile-before-change", context.get());        
01362     }
01363 
01364     // Roaming upload
01365     // Tolerate errors. Maybe the roaming extension isn't installed.
01366     nsCOMPtr <nsISessionRoaming> roam =
01367       do_GetService(NS_SESSIONROAMING_CONTRACTID, &rv);
01368     if (NS_SUCCEEDED(rv))
01369       roam->EndSession();
01370 
01371     gDirServiceProvider->SetProfileDir(nsnull);
01372     UpdateCurrentProfileModTime(PR_TRUE);
01373     mCurrentProfileAvailable = PR_FALSE;
01374     mCurrentProfileName.Truncate(0);
01375     
01376     return NS_OK;
01377 }
01378 
01379 
01380 #define SALT_SIZE 8
01381 #define TABLE_SIZE 36
01382 
01383 static const char kSaltExtensionCString[] = ".slt";
01384 #define kSaltExtensionCString_Len PRUint32(sizeof(kSaltExtensionCString)-1)
01385 
01386 static const char table[] = 
01387        { 'a','b','c','d','e','f','g','h','i','j',
01388          'k','l','m','n','o','p','q','r','s','t',
01389          'u','v','w','x','y','z','0','1','2','3',
01390          '4','5','6','7','8','9'};
01391 
01392 // for security, add a level of indirection:
01393 // an extra directory with a hard to guess name.
01394 
01395 nsresult
01396 nsProfile::AddLevelOfIndirection(nsIFile *aDir)
01397 {
01398   nsresult rv;
01399   PRBool exists = PR_FALSE;
01400   if (!aDir) return NS_ERROR_NULL_POINTER;
01401 
01402   // check if aDir/prefs.js exists, if so, use it.
01403   // else, check if aDir/*.slt exists, if so, use it.
01404   // else, do the salt
01405   nsCOMPtr<nsIFile> prefFile;
01406   rv = aDir->Clone(getter_AddRefs(prefFile));
01407   NS_ENSURE_SUCCESS(rv,rv);
01408 
01409   rv = prefFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
01410   NS_ENSURE_SUCCESS(rv,rv);
01411 
01412   rv = prefFile->Exists(&exists);
01413   NS_ENSURE_SUCCESS(rv,rv);
01414 
01415   if (exists) {
01416        // there is a prefs.js file in aDir, so just use aDir and don't salt
01417        return NS_OK;
01418   }
01419 
01420   // no prefs.js, now search for a .slt directory
01421   PRBool hasMore = PR_FALSE;
01422   PRBool isDir = PR_FALSE;
01423   nsCOMPtr<nsISimpleEnumerator> dirIterator;
01424   rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
01425   NS_ENSURE_SUCCESS(rv,rv);
01426 
01427   rv = dirIterator->HasMoreElements(&hasMore);
01428   NS_ENSURE_SUCCESS(rv,rv);
01429 
01430   nsCOMPtr<nsIFile> dirEntry;
01431 
01432   while (hasMore) {
01433     rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
01434     if (NS_SUCCEEDED(rv)) {
01435       rv = dirEntry->IsDirectory(&isDir);
01436       if (NS_SUCCEEDED(rv) && isDir) {
01437         nsCAutoString leafName;
01438         rv = dirEntry->GetNativeLeafName(leafName);
01439               if (NS_SUCCEEDED(rv) && !leafName.IsEmpty()) {
01440                 PRUint32 length = leafName.Length();
01441                 // check if the filename is the right length, len("xxxxxxxx.slt")
01442                 if (length == (SALT_SIZE + kSaltExtensionCString_Len)) {
01443                      // check that the filename ends with ".slt"
01444                      if (nsCRT::strncmp(leafName.get() + SALT_SIZE,
01445                          kSaltExtensionCString,
01446                          kSaltExtensionCString_Len) == 0) {
01447                        // found a salt directory, use it
01448                        rv = aDir->AppendNative(leafName);
01449                        return rv;
01450                      }
01451                 }
01452               }
01453       }
01454     }
01455     rv = dirIterator->HasMoreElements(&hasMore);
01456     NS_ENSURE_SUCCESS(rv,rv);
01457   }
01458   
01459   // if we get here, we need to add the extra directory
01460 
01461   // turn PR_Now() into milliseconds since epoch
01462   // and salt rand with that.
01463   double fpTime;
01464   LL_L2D(fpTime, PR_Now());
01465   srand((uint)(fpTime * 1e-6 + 0.5));     // use 1e-6, granularity of PR_Now() on the mac is seconds
01466 
01467   nsCAutoString saltStr;
01468   PRInt32 i;
01469   for (i=0;i<SALT_SIZE;i++) {
01470        saltStr.Append(table[rand()%TABLE_SIZE]);
01471   }
01472   saltStr.Append(kSaltExtensionCString, kSaltExtensionCString_Len);
01473 #ifdef DEBUG_profile_verbose
01474   printf("directory name: %s\n",saltStr.get());
01475 #endif
01476 
01477   rv = aDir->AppendNative(saltStr);
01478   NS_ENSURE_SUCCESS(rv,rv);
01479 
01480   exists = PR_FALSE;
01481   rv = aDir->Exists(&exists);
01482   NS_ENSURE_SUCCESS(rv,rv);
01483   if (!exists) {
01484     rv = aDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
01485     NS_ENSURE_SUCCESS(rv,rv);
01486   }
01487        
01488   return NS_OK;
01489 }
01490 
01491 nsresult nsProfile::IsProfileDirSalted(nsIFile *profileDir, PRBool *isSalted)
01492 {
01493     nsresult rv;
01494     NS_ENSURE_ARG_POINTER(isSalted);
01495     *isSalted = PR_FALSE;
01496     
01497     // 1. The name of the profile dir has to end in ".slt"
01498     nsCAutoString leafName;
01499     rv = profileDir->GetNativeLeafName(leafName);
01500     if (NS_FAILED(rv)) return rv;
01501 
01502     PRBool endsWithSalt = PR_FALSE;    
01503     if (leafName.Length() >= kSaltExtensionCString_Len)
01504     {
01505         nsReadingIterator<char> stringEnd;
01506         leafName.EndReading(stringEnd);
01507 
01508         nsReadingIterator<char> stringStart = stringEnd;
01509         stringStart.advance( -(NS_STATIC_CAST(PRInt32, kSaltExtensionCString_Len)) );
01510 
01511         endsWithSalt =
01512             Substring(stringStart, stringEnd).Equals(kSaltExtensionCString);
01513     }
01514     if (!endsWithSalt)
01515         return NS_OK;
01516     
01517     // 2. The profile dir has to be its parent's only child.    
01518     nsCOMPtr<nsIFile> parentDir;
01519     rv = profileDir->GetParent(getter_AddRefs(parentDir));
01520     if (NS_FAILED(rv)) return rv;
01521 
01522     PRBool hasMore;
01523     nsCOMPtr<nsISimpleEnumerator> dirIterator;
01524     rv = parentDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
01525     if (NS_FAILED(rv)) return rv;
01526     
01527     PRInt32 numChildren = 0;
01528     rv = dirIterator->HasMoreElements(&hasMore);
01529     
01530     while (NS_SUCCEEDED(rv) && hasMore && numChildren <= 1) {
01531         nsCOMPtr<nsIFile> child;
01532         rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(child));    
01533         if (NS_SUCCEEDED(rv))
01534             ++numChildren;
01535         rv = dirIterator->HasMoreElements(&hasMore);
01536     }
01537     if (NS_SUCCEEDED(rv) && numChildren == 1)
01538         *isSalted = PR_TRUE;
01539     
01540     return NS_OK;
01541 }
01542 
01543 /*
01544  * Setters
01545  */
01546 
01547 // Sets the current profile directory
01548 nsresult nsProfile::SetProfileDir(const PRUnichar *profileName, nsIFile *profileDir)
01549 {
01550     NS_ENSURE_ARG(profileName);
01551     NS_ENSURE_ARG(profileDir);   
01552 
01553     nsresult rv = NS_OK;
01554  
01555     // Need to ensure that this directory exists
01556     PRBool exists;
01557     rv = profileDir->Exists(&exists);
01558     if (NS_SUCCEEDED(rv) && !exists)
01559         rv = profileDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
01560     if (NS_FAILED(rv)) 
01561         return rv;
01562     
01563     nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(profileDir));
01564     NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);                
01565 
01566     ProfileStruct* aProfile = new ProfileStruct();
01567     NS_ENSURE_TRUE(aProfile, NS_ERROR_OUT_OF_MEMORY);
01568 
01569     aProfile->profileName = profileName;
01570     aProfile->SetResolvedProfileDir(localFile);
01571     aProfile->isMigrated = PR_TRUE;
01572     aProfile->isImportType = PR_FALSE;
01573 
01574     // convert "now" from microsecs to millisecs
01575     PRInt64 oneThousand = LL_INIT(0, 1000);
01576     PRInt64 nowInMilliSecs = PR_Now();
01577     LL_DIV(aProfile->creationTime, nowInMilliSecs, oneThousand); 
01578 
01579     gProfileDataAccess->SetValue(aProfile);
01580     
01581     delete aProfile;
01582 
01583     return rv;
01584 }
01585 
01586 // Creates a new profile with UILocale and contentLocale
01587 NS_IMETHODIMP 
01588 nsProfile::CreateNewProfileWithLocales(const PRUnichar* profileName, 
01589                             const PRUnichar* nativeProfileDir,
01590                             const PRUnichar* aUILocale,
01591                             const PRUnichar* aContentLocale,
01592                             PRBool useExistingDir)
01593 {
01594     NS_ENSURE_ARG_POINTER(profileName);   
01595 
01596     nsresult rv = NS_OK;
01597 
01598 #if defined(DEBUG_profile)
01599     {
01600       printf("ProfileManager : CreateNewProfileWithLocales\n");
01601 
01602       printf("Profile Name: %s\n", NS_LossyConvertUCS2toASCII(profileName).get());
01603 
01604       if (nativeProfileDir)
01605         printf("Profile Dir: %s\n", NS_LossyConvertUCS2toASCII(nativeProfileDir).get());
01606     }
01607 #endif
01608 
01609     nsCOMPtr<nsIFile> profileDir;
01610     PRBool exists;
01611     
01612     if (!nativeProfileDir)
01613     {
01614         // They didn't specify a directory path...
01615                 
01616         rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(profileDir));
01617         if (NS_FAILED(rv)) return rv;
01618         rv = profileDir->Exists(&exists);
01619         if (NS_FAILED(rv)) return rv;        
01620         if (!exists)
01621             profileDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
01622 
01623         // append profile name
01624         profileDir->Append(nsDependentString(profileName));
01625     }
01626     else {
01627     
01628         rv = NS_NewLocalFile(nsDependentString(nativeProfileDir), PR_TRUE, (nsILocalFile **)((nsIFile **)getter_AddRefs(profileDir)));
01629         if (NS_FAILED(rv)) return rv;
01630 
01631         // this prevents people from choosing their profile directory
01632         // or another directory, and remove it when they delete the profile.
01633         // append profile name
01634         profileDir->Append(nsDependentString(profileName));
01635     }
01636 
01637 
01638     // Make profile directory unique only when the user 
01639     // decides to not use an already existing profile directory
01640     if (!useExistingDir) {
01641         rv = profileDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
01642         if (NS_FAILED(rv)) return rv;
01643     }
01644 
01645 #if defined(DEBUG_profile_verbose)
01646     printf("before SetProfileDir\n");
01647 #endif
01648 
01649     rv = profileDir->Exists(&exists);
01650     if (NS_FAILED(rv)) return rv;        
01651     if (!exists)
01652     {
01653         rv = profileDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
01654         if (NS_FAILED(rv)) return rv;
01655         useExistingDir = PR_FALSE;
01656     }
01657 
01658     // since the directory didn't exist, add the indirection
01659     rv = AddLevelOfIndirection(profileDir);
01660     if (NS_FAILED(rv)) return rv;
01661 
01662     // Set the directory value and add the entry to the registry tree.
01663     rv = SetProfileDir(profileName, profileDir);
01664 
01665 #if defined(DEBUG_profile_verbose)
01666     printf("after SetProfileDir\n");
01667 #endif
01668 
01669     // Get profile defaults folder..
01670     nsCOMPtr <nsIFile> profDefaultsDir;
01671     rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR, getter_AddRefs(profDefaultsDir));
01672     if (NS_FAILED(rv)) return rv;
01673 
01674     nsCOMPtr<nsIChromeRegistrySea> chromeRegistry =
01675         do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
01676     if (NS_SUCCEEDED(rv)) {
01677 
01678         nsCAutoString uiLocale, contentLocale;
01679         LossyCopyUTF16toASCII(aUILocale, uiLocale);
01680         LossyCopyUTF16toASCII(aContentLocale, contentLocale);
01681 
01682         // When aUILocale == null or aContentLocale == null, set those
01683         // from default values which are from default or from command
01684         // line options
01685 
01686         // This fallback is for CreateNewProfile() of
01687         // CreateDefaultProfile() and ProcessArgs() Those functions
01688         // call CreateNewProfile(locale=null). We should consider
01689         // default values or specified values of locales for
01690         // CreateDefaultProfile() and ProcessArgs().
01691 
01692         // We can get preferred UILocale and contentLocale (specified
01693         // -UILocale and -contentLocale) by GetSelectedLocale() which
01694         // is done in nsAppRunner.cpp::InstallGlobalLocale()
01695 
01696         nsCOMPtr<nsIChromeRegistrySea> packageRegistry = do_QueryInterface(chromeRegistry);
01697         if (uiLocale.IsEmpty() && packageRegistry) {
01698             nsCAutoString currentUILocaleName;
01699             rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
01700                                                     currentUILocaleName);
01701             if (NS_SUCCEEDED(rv)) {
01702                 uiLocale = currentUILocaleName;
01703             }
01704         }
01705 
01706         if (contentLocale.IsEmpty()) {
01707             nsCAutoString currentContentLocaleName;
01708             rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global-region"),
01709                                                     currentContentLocaleName);
01710             if (NS_SUCCEEDED(rv)) {
01711                 contentLocale = currentContentLocaleName;
01712             }
01713         }
01714 
01715 #if defined(DEBUG_profile_verbose)
01716         printf(" uiLocale=%s\n", uiLocale.get());
01717         printf(" contentLocale=%s\n", contentLocale.get());
01718 #endif
01719 
01720         nsCAutoString pathBuf;
01721         rv = profileDir->GetNativePath(pathBuf);
01722         NS_ENSURE_SUCCESS(rv, rv);
01723 
01724         nsCAutoString fileStr;
01725         rv = NS_GetURLSpecFromFile(profileDir, fileStr);
01726         if (NS_FAILED(rv)) return rv;
01727 
01728         if (!uiLocale.IsEmpty()) {
01729             rv = chromeRegistry->SelectLocaleForProfile(uiLocale, 
01730                                                         NS_ConvertUTF8toUCS2(fileStr).get());
01731             // Remember which profile has been created with the UILocale
01732             // didn't use gProfileDataAccess because just needed one time
01733             if (NS_SUCCEEDED(rv)) {
01734                 nsCStringKey key(pathBuf);
01735                 gLocaleProfiles->Put(&key, (void*)PR_TRUE);
01736             }
01737         }
01738 
01739         //need to set skin info here
01740         nsCAutoString currentSkinName;
01741         rv = packageRegistry->GetSelectedSkin(NS_LITERAL_CSTRING("global"),currentSkinName);
01742         if (!currentSkinName.IsEmpty()) {
01743             rv = chromeRegistry->SelectSkinForProfile(currentSkinName,
01744                                          NS_ConvertUTF8toUCS2(fileStr).get());
01745         }
01746 
01747         if (!contentLocale.IsEmpty()) {
01748             // caller prefers locale subdir
01749             nsCOMPtr<nsIFile> locProfDefaultsDir;
01750             rv = profDefaultsDir->Clone(getter_AddRefs(locProfDefaultsDir));
01751             if (NS_FAILED(rv)) return rv;
01752         
01753             locProfDefaultsDir->AppendNative(contentLocale);
01754             rv = locProfDefaultsDir->Exists(&exists);
01755             if (NS_SUCCEEDED(rv) && exists) {
01756                 profDefaultsDir = locProfDefaultsDir; // transfers ownership
01757 #if defined(DEBUG_profile_verbose)
01758                 nsCAutoString profilePath;
01759                 rv = profDefaultsDir->GetNativePath(profilePath);
01760                 if (NS_SUCCEEDED(rv))
01761                     printf(" profDefaultsDir is set to: %s\n", profilePath.get());
01762 #endif
01763             }
01764 
01765             rv = chromeRegistry->SelectLocaleForProfile(contentLocale, 
01766                                                         NS_ConvertUTF8toUCS2(fileStr).get());
01767             // Remember which profile has been created with the UILocale
01768             // didn't use gProfileDataAccess because just needed one time
01769             if (NS_SUCCEEDED(rv)) {
01770                 nsCStringKey key(pathBuf);
01771                 gLocaleProfiles->Put(&key, (void*)PR_TRUE);
01772             }
01773         }
01774     }
01775 
01776     // Copy contents from defaults folder.
01777     rv = profDefaultsDir->Exists(&exists);
01778     if (NS_SUCCEEDED(rv) && exists && (!useExistingDir))
01779     {
01780         RecursiveCopy(profDefaultsDir, profileDir);
01781     }
01782 
01783     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
01784     gProfileDataAccess->UpdateRegistry(nsnull);
01785     
01786     return NS_OK;
01787 }      
01788 
01789 
01790 // Rename a old profile to new profile.
01791 // Copies all the keys from old profile to new profile.
01792 
01793 // Creates a new profile
01794 NS_IMETHODIMP 
01795 nsProfile::CreateNewProfile(const PRUnichar* profileName, 
01796                             const PRUnichar* nativeProfileDir,
01797                             const PRUnichar* langcode,
01798                             PRBool useExistingDir)
01799 {
01800     return CreateNewProfileWithLocales(profileName,nativeProfileDir,langcode,nsnull,useExistingDir);
01801 }
01802 
01803 
01804 // Rename a old profile to new profile.
01805 // Copies all the keys from old profile to new profile.
01806 // Deletes the old profile from the registry
01807 NS_IMETHODIMP 
01808 nsProfile::RenameProfile(const PRUnichar* oldName, const PRUnichar* newName)
01809 {
01810     NS_ENSURE_ARG_POINTER(oldName);   
01811     NS_ENSURE_ARG_POINTER(newName);   
01812 
01813     nsresult rv = NS_OK;
01814 
01815 #if defined(DEBUG_profile)
01816     {
01817       printf("ProfileManager : Renaming profile\n");
01818 
01819       nsCAutoString temp1; temp1.AssignWithConversion(oldName);
01820       printf("Old name:  %s\n", NS_LossyConvertUCS2toASCII(oldName).get());
01821 
01822       nsCAutoString temp2; temp2.AssignWithConversion(newName);
01823       printf("New name:  %s\n", NS_LossyConvertUCS2toASCII(newName).get());
01824     }
01825 #endif
01826 
01827     PRBool exists;
01828     rv = ProfileExists(newName, &exists);
01829     if (NS_FAILED(rv)) return rv;
01830     
01831     // That profile already exists...
01832     if (exists) {
01833 #if defined(DEBUG_profile)  
01834         printf("ProfileManager : Rename Operation failed : Profile exists. Provide a different new name for profile.\n");
01835 #endif
01836         return NS_ERROR_FAILURE;
01837     }
01838 
01839     PRBool renamedIsCurrent = mCurrentProfileName.Equals(oldName);
01840 
01841     // Copy reg keys
01842     rv = CopyRegKey(oldName, newName);
01843     if (NS_FAILED(rv)) return rv;
01844      
01845     // Delete old profile entry
01846     rv = DeleteProfile(oldName, PR_FALSE /* don't delete files */);
01847 
01848     // If the profile being renamed is the current profile,
01849     // change the current profile name.
01850     if (renamedIsCurrent) {
01851         gProfileDataAccess->SetCurrentProfile(newName);
01852         gProfileDataAccess->mForgetProfileCalled = PR_FALSE;
01853         mCurrentProfileName.Assign(newName);    
01854         mCurrentProfileAvailable = PR_TRUE;
01855     }
01856 
01857     if (NS_FAILED(rv)) return rv;
01858      
01859        /* note, we do not rename the directory on disk to the new name
01860         * this is on purpose.
01861      *
01862         * we don't require the directory name to match the profile name, 
01863         * but it usually does.  
01864         * (the pairing of values occurs in the profile registry)
01865         * 
01866         * Imagine this scenario:
01867         * 1) user creates a profile "foo" and the directory gets named "foo".
01868         * 2) user creates a profile "bar" and the directory gets named "bar"
01869         * 3) user deletes the profile "foo", but chooses not to delete the files on disk.  (they are given this option when deleting a profile)
01870         * 4) user renames "bar" profile to "foo", but still uses the directory named "bar" on disk
01871         *
01872         * bad things would happen if we tried to rename the directory
01873         */
01874 
01875     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
01876     gProfileDataAccess->UpdateRegistry(nsnull);
01877 
01878     return NS_OK;
01879 }
01880 
01881 // Copy old profile entries to the new profile
01882 // In the process creates new profile subtree.
01883 nsresult nsProfile::CopyRegKey(const PRUnichar *oldProfile, const PRUnichar *newProfile)
01884 {
01885     NS_ENSURE_ARG_POINTER(oldProfile);   
01886     NS_ENSURE_ARG_POINTER(newProfile);   
01887 
01888     nsresult rv = NS_OK;
01889 
01890     ProfileStruct    *aProfile;
01891 
01892     rv = gProfileDataAccess->GetValue(oldProfile, &aProfile);
01893     if (NS_FAILED(rv)) return rv;
01894 
01895     aProfile->profileName        = newProfile;
01896 
01897     rv = gProfileDataAccess->SetValue(aProfile);
01898 
01899        delete aProfile;
01900 
01901     return rv;
01902 }
01903 
01904 NS_IMETHODIMP nsProfile::ForgetCurrentProfile()
01905 {
01906     nsresult rv = NS_OK;
01907 
01908     // Remove the current profile subtree from the registry.
01909     PRUnichar tmp[] = { '\0' };
01910 
01911     gProfileDataAccess->SetCurrentProfile(tmp);
01912     if (NS_FAILED(rv)) return rv;  
01913 
01914     gProfileDataAccess->mForgetProfileCalled = PR_TRUE;
01915     mCurrentProfileAvailable = PR_FALSE;
01916     mCurrentProfileName.Truncate(0);
01917     
01918     return rv;
01919 }
01920 
01921 // Delete a profile from the registry
01922 // Not deleting the directories on the harddisk yet.
01923 // 4.x kind of confirmation need to be implemented yet
01924 NS_IMETHODIMP nsProfile::DeleteProfile(const PRUnichar* profileName, PRBool canDeleteFiles)
01925 {
01926     NS_ENSURE_ARG_POINTER(profileName);   
01927 
01928     nsresult rv;
01929  
01930     nsXPIDLString currProfile;
01931     rv = GetCurrentProfile(getter_Copies(currProfile));
01932     if (NS_SUCCEEDED(rv) && !nsCRT::strcmp(profileName, currProfile)) {
01933         rv = ForgetCurrentProfile();
01934         if (NS_FAILED(rv)) return rv;
01935     }
01936     rv = NS_OK;
01937     
01938     // If user asks for it, delete profile directory
01939     if (canDeleteFiles) {
01940     
01941         nsCOMPtr<nsIFile> profileDir;
01942         rv = GetProfileDir(profileName, getter_AddRefs(profileDir));
01943         if (NS_FAILED(rv)) return rv;
01944         
01945         PRBool exists;
01946         rv = profileDir->Exists(&exists);
01947         if (NS_FAILED(rv)) return rv;
01948         
01949         if (exists) {
01950 
01951             // The profile dir may be located inside a salted dir.
01952             // If so, according to IsProfileDirSalted,
01953             // delete the parent dir as well.
01954             
01955             nsCOMPtr<nsIFile> dirToDelete(profileDir);
01956             PRBool isSalted;
01957             rv = IsProfileDirSalted(profileDir, &isSalted);
01958             if (NS_SUCCEEDED(rv) && isSalted) {
01959                 nsCOMPtr<nsIFile> parentDir;
01960                 rv = profileDir->GetParent(getter_AddRefs(parentDir));
01961                 if (NS_SUCCEEDED(rv))
01962                     dirToDelete = parentDir;
01963             }
01964             rv = dirToDelete->Remove(PR_TRUE);
01965         }
01966     }
01967 
01968     // Remove the subtree from the registry.
01969     gProfileDataAccess->RemoveSubTree(profileName);
01970     if (NS_FAILED(rv)) return rv;
01971 
01972     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
01973     gProfileDataAccess->UpdateRegistry(nsnull);
01974 
01975     return rv;
01976 }
01977 
01978 
01979 NS_IMETHODIMP nsProfile::GetProfileList(PRUint32 *length, PRUnichar ***profileNames)
01980 {
01981     NS_ENSURE_ARG_POINTER(length);
01982     *length = 0;
01983     NS_ENSURE_ARG_POINTER(profileNames);
01984     *profileNames = nsnull;
01985     
01986     return gProfileDataAccess->GetProfileList(nsIProfileInternal::LIST_ONLY_NEW, length, profileNames);
01987 }
01988  
01989 
01990 NS_IMETHODIMP nsProfile::GetProfileListX(PRUint32 whichKind, PRUint32 *length, PRUnichar ***profileNames)
01991 {
01992     NS_ENSURE_ARG_POINTER(length);
01993     *length = 0;
01994     NS_ENSURE_ARG_POINTER(profileNames);
01995     *profileNames = nsnull;
01996     
01997     if (whichKind == nsIProfileInternal::LIST_FOR_IMPORT)
01998         Update4xProfileInfo();
01999     return gProfileDataAccess->GetProfileList(whichKind, length, profileNames);
02000 }
02001 
02002 // this will add all the 4x profiles (with isImportType flag set) to the 
02003 // profiles list. The adding of profiles is done only once per session.
02004 nsresult nsProfile::Update4xProfileInfo()
02005 {
02006     nsresult rv = NS_OK;
02007 
02008 #ifndef XP_BEOS
02009     nsCOMPtr<nsIFile> oldRegFile;
02010     rv = GetOldRegLocation(getter_AddRefs(oldRegFile));
02011     if (NS_SUCCEEDED(rv))
02012     rv = gProfileDataAccess->Get4xProfileInfo(oldRegFile, PR_TRUE);
02013 #endif
02014 
02015     return rv;
02016 }
02017 
02018 nsresult nsProfile::LoadNewProfilePrefs()
02019 {
02020     nsresult rv;
02021     nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
02022     if (NS_FAILED(rv)) return rv;
02023     
02024     prefs->ResetUserPrefs();
02025     prefs->ReadUserPrefs(nsnull);
02026 
02027     return NS_OK;
02028 }
02029 
02030 nsresult nsProfile::GetOldRegLocation(nsIFile **aOldRegFile)
02031 {
02032     NS_ENSURE_ARG_POINTER(aOldRegFile);
02033     *aOldRegFile = nsnull;
02034     nsresult rv = NS_OK;
02035     
02036     // For XP_UNIX there was no registry for 4.x profiles.
02037     // Return nsnull for the file, and NS_OK - we succeeded in doing nothing.
02038     
02039 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_MAC) || defined(XP_MACOSX)
02040     nsCOMPtr<nsIFile> oldRegFile;
02041 
02042 #if defined(XP_WIN)
02043     rv = NS_GetSpecialDirectory(NS_WIN_WINDOWS_DIR, getter_AddRefs(oldRegFile));
02044 #elif defined(XP_OS2)
02045     rv = NS_GetSpecialDirectory(NS_OS2_DIR, getter_AddRefs(oldRegFile));
02046 #elif defined(XP_MAC) || defined(XP_MACOSX)
02047     rv = NS_GetSpecialDirectory(NS_MAC_PREFS_DIR, getter_AddRefs(oldRegFile));
02048 #endif
02049 
02050     if (NS_FAILED(rv))
02051         return rv;
02052     rv = oldRegFile->AppendNative(nsDependentCString(OLD_REGISTRY_FILE_NAME));
02053     if (NS_FAILED(rv))
02054         return rv;
02055     NS_ADDREF(*aOldRegFile = oldRegFile);
02056 #endif
02057 
02058     return rv;
02059 }
02060 
02061 nsresult nsProfile::UpdateCurrentProfileModTime(PRBool updateRegistry)
02062 {
02063     nsresult rv;
02064 
02065     // convert "now" from microsecs to millisecs
02066     PRInt64 oneThousand = LL_INIT(0, 1000);
02067     PRInt64 nowInMilliSecs = PR_Now();
02068     LL_DIV(nowInMilliSecs, nowInMilliSecs, oneThousand); 
02069     
02070     rv = gProfileDataAccess->SetProfileLastModTime(mCurrentProfileName.get(), nowInMilliSecs);
02071     if (NS_SUCCEEDED(rv) && updateRegistry) {
02072         gProfileDataAccess->mProfileDataChanged = PR_TRUE;
02073         gProfileDataAccess->UpdateRegistry(nsnull);
02074     }
02075     return rv;
02076 }
02077 
02078 // Migrate profile information from the 4x registry to 5x registry.
02079 NS_IMETHODIMP nsProfile::MigrateProfileInfo()
02080 {
02081     nsresult rv = NS_OK;
02082 
02083 #ifndef XP_BEOS
02084     nsCOMPtr<nsIFile> oldRegFile;
02085     rv = GetOldRegLocation(getter_AddRefs(oldRegFile));
02086     if (NS_SUCCEEDED(rv)) {
02087     rv = gProfileDataAccess->Get4xProfileInfo(oldRegFile, PR_FALSE);
02088     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
02089     gProfileDataAccess->UpdateRegistry(nsnull);
02090     }
02091 #endif
02092 
02093        return rv;
02094 }
02095 
02096 nsresult
02097 nsProfile::CopyDefaultFile(nsIFile *profDefaultsDir, nsIFile *newProfDir, const nsACString &fileName)
02098 {
02099     nsresult rv;
02100     nsCOMPtr<nsIFile> defaultFile;
02101     PRBool exists;
02102     
02103     rv = profDefaultsDir->Clone(getter_AddRefs(defaultFile));
02104     if (NS_FAILED(rv)) return rv;
02105     
02106     defaultFile->AppendNative(fileName);
02107     rv = defaultFile->Exists(&exists);
02108     if (NS_FAILED(rv)) return rv;
02109     if (exists)
02110         rv = defaultFile->CopyToNative(newProfDir, fileName);
02111     else
02112         rv = NS_ERROR_FILE_NOT_FOUND;
02113 
02114        return rv;
02115 }
02116 
02117 nsresult
02118 nsProfile::DefineLocaleDefaultsDir()
02119 {
02120     nsresult rv;
02121     
02122     nsCOMPtr<nsIProperties> directoryService = 
02123              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
02124     NS_ENSURE_TRUE(directoryService, NS_ERROR_FAILURE);    
02125 
02126     nsCOMPtr<nsIFile> localeDefaults;
02127     rv = directoryService->Get(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR, NS_GET_IID(nsIFile), getter_AddRefs(localeDefaults));
02128     if (NS_SUCCEEDED(rv))
02129     {
02130         nsCOMPtr<nsIChromeRegistrySea> packageRegistry = 
02131                  do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
02132         if (NS_SUCCEEDED(rv))
02133         {
02134             nsCAutoString localeName;
02135             rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global-region"), localeName);
02136             if (NS_SUCCEEDED(rv))
02137                 rv = localeDefaults->AppendNative(localeName);
02138         }
02139         rv = directoryService->Set(NS_APP_PROFILE_DEFAULTS_50_DIR, localeDefaults);
02140     }
02141     return rv;
02142 }
02143 
02144 // Migrate a selected profile
02145 // Set the profile to the current profile....debatable.
02146 // Calls PrefMigration service to do the Copy and Diverge
02147 // of 4x Profile information
02148 nsresult 
02149 nsProfile::MigrateProfileInternal(const PRUnichar* profileName,
02150                                   nsIFile* oldProfDir,
02151                                   nsIFile* newProfDir)
02152 {
02153     NS_ENSURE_ARG_POINTER(profileName);   
02154 
02155 #if defined(DEBUG_profile)
02156     printf("Inside Migrate Profile routine.\n" );
02157 #endif
02158 
02159     // Call migration service to do the work.
02160 
02161     nsresult rv;
02162     nsCOMPtr <nsIPrefMigration> pPrefMigrator =
02163             do_CreateInstance(kPrefMigrationCID, &rv);
02164     if (NS_FAILED(rv)) return rv;
02165         
02166     nsCOMPtr<nsILocalFile> oldProfDirLocal(do_QueryInterface(oldProfDir, &rv));
02167     if (NS_FAILED(rv)) return rv;    
02168     nsCOMPtr<nsILocalFile> newProfDirLocal(do_QueryInterface(newProfDir, &rv));
02169     if (NS_FAILED(rv)) return rv;
02170         
02171     nsCAutoString oldProfDirStr;
02172     nsCAutoString newProfDirStr;
02173 
02174     rv = oldProfDirLocal->GetPersistentDescriptor(oldProfDirStr);
02175     if (NS_FAILED(rv)) return rv;
02176     rv = newProfDirLocal->GetPersistentDescriptor(newProfDirStr);
02177     if (NS_FAILED(rv)) return rv;
02178 
02179     // you can do this a bunch of times.
02180     rv = pPrefMigrator->AddProfilePaths(oldProfDirStr.get(), newProfDirStr.get());  
02181 
02182     rv = pPrefMigrator->ProcessPrefs(PR_TRUE); // param is ignored
02183     if (NS_FAILED(rv)) return rv;
02184 
02185     // check for diskspace errors  
02186     nsresult errorCode;   
02187     errorCode = pPrefMigrator->GetError();
02188 
02189     // In either of the cases below we have to return error to make
02190     // app understand that migration has failed.
02191     if (errorCode == MIGRATION_CREATE_NEW)
02192     {
02193         PRInt32 numProfiles = 0;
02194         ShowProfileWizard();
02195 
02196         // When the automigration process fails because of disk space error,
02197         // we present user a create profile wizard if the user chooses to create a 
02198         // a profile then. But then the user may click on cancel on that dialog...
02199         // So, if the user clicks on cancel, the number of profiles should be 
02200         // ZERO at the point for the user who failed to automigrate single 4x profile.
02201         // On such condition, set mDiskSpaceErrorQuitCalled to allow user to quit the app.
02202         // If the user is presented with profilemanager dialog with multiple 4x profiles
02203         // to migrate, value of mDiskSpaceErrorQuitCalled does not matter as it gets ignored..
02204         // If a single profile needs automigration and no confirmation 
02205         // is needed for that operation mAutomigrate is set to false. 
02206         if (!mAutomigrate)
02207         {
02208             GetProfileCount(&numProfiles);
02209             if (numProfiles == 0)
02210                 mDiskSpaceErrorQuitCalled = PR_TRUE;
02211         }
02212         mOutofDiskSpace = PR_TRUE;
02213         return NS_ERROR_FAILURE;
02214     }
02215     else if (errorCode == MIGRATION_CANCEL) 
02216     {
02217         // When the automigration process fails because of disk space error,
02218         // user may choose to simply quit the app from the dialog presented 
02219         // by pref-migrator. So, set mDiskSpaceErrorQuitCalled to allow user 
02220         // to quit the app in such a case.
02221         // If the user is presented with profilemanager dialog with multiple 4x profiles
02222         // to migrate, value of mDiskSpaceErrorQuitCalled does not matter as it gets ignored..
02223         // If a single profile needs automigration and no confirmation 
02224         // is needed for that operation mAutomigrate is set to false. 
02225         if (!mAutomigrate)
02226             mDiskSpaceErrorQuitCalled = PR_TRUE;
02227 
02228         ForgetCurrentProfile();
02229         mOutofDiskSpace = PR_TRUE;
02230         return NS_ERROR_FAILURE;
02231     }
02232     else if (errorCode != MIGRATION_SUCCESS) 
02233     {
02234         return NS_ERROR_FAILURE;
02235     }
02236 
02237     // No longer copying the default 5.0 profile files into
02238     // the migrated profile. Check for them as requested.
02239        
02240     rv = SetProfileDir(profileName, newProfDir);
02241     if (NS_FAILED(rv)) return rv;
02242 
02243     gProfileDataAccess->SetMigratedFromDir(profileName, oldProfDirLocal);
02244     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
02245     gProfileDataAccess->UpdateRegistry(nsnull);
02246 
02247     return rv;
02248 }
02249 
02250 NS_IMETHODIMP 
02251 nsProfile::MigrateProfile(const PRUnichar* profileName)
02252 {
02253     NS_ENSURE_ARG(profileName);   
02254 
02255     nsresult rv = NS_OK;
02256 
02257     nsCOMPtr<nsIFile> oldProfDir;    
02258     nsCOMPtr<nsIFile> newProfDir;
02259     nsCOMPtr<nsIPrefBranch> prefBranch;
02260     nsXPIDLCString profMigDir;
02261  
02262     rv = GetProfileDir(profileName, getter_AddRefs(oldProfDir));
02263     if (NS_FAILED(rv)) 
02264       return rv;
02265    
02266     // Check PREF_MIGRATION_BEHAVIOR for how to set profiles root
02267     // 0 - use NS_APP_USER_PROFILES_ROOT_DIR
02268     // 1 - create one based on the NS4.x profile root
02269     // 2 - use if not empty PREF_MIGRATION_DIRECTORY
02270     PRInt32 profRootBehavior = 0;
02271     nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
02272     if (NS_SUCCEEDED(rv)) {
02273       rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
02274       if (NS_SUCCEEDED(rv))
02275         (void) prefBranch->GetIntPref(PREF_MIGRATION_BEHAVIOR, &profRootBehavior);
02276     }
02277 
02278     switch (profRootBehavior) {
02279 
02280       case 1:
02281         rv = oldProfDir->Clone(getter_AddRefs(newProfDir));
02282         if (NS_FAILED(rv)) 
02283           return rv;
02284         rv = newProfDir->SetNativeLeafName(NS_LITERAL_CSTRING("Profiles"));
02285         if (NS_FAILED(rv)) 
02286           return rv;
02287         break;
02288 
02289       case 2:
02290         rv = prefBranch->GetCharPref(PREF_MIGRATION_DIRECTORY, getter_Copies(profMigDir));
02291         if (NS_SUCCEEDED(rv) && !profMigDir.IsEmpty()) {
02292           nsCOMPtr<nsILocalFile> localFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
02293           NS_ENSURE_SUCCESS(rv, rv);
02294           rv = localFile->InitWithNativePath(nsDependentCString(profMigDir));
02295           if (NS_SUCCEEDED(rv)) {
02296             newProfDir = do_QueryInterface(localFile, &rv);
02297             if (NS_FAILED(rv)) 
02298               return rv;
02299           }
02300         }
02301         break;
02302 
02303       default:
02304         break;
02305 
02306     }
02307     if (!newProfDir) {
02308       rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(newProfDir));
02309       if (NS_FAILED(rv)) 
02310         return rv;
02311     }
02312 
02313     rv = newProfDir->Append(nsDependentString(profileName));
02314     if (NS_FAILED(rv)) 
02315       return rv;
02316     
02317     rv = newProfDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
02318     if (NS_FAILED(rv)) 
02319       return rv;
02320     
02321     // always create level indirection when migrating
02322     rv = AddLevelOfIndirection(newProfDir);
02323     if (NS_FAILED(rv))
02324       return rv;
02325 
02326     return MigrateProfileInternal(profileName, oldProfDir, newProfDir);
02327 }
02328 
02329 NS_IMETHODIMP 
02330 nsProfile::RemigrateProfile(const PRUnichar* profileName)
02331 {
02332     NS_ENSURE_ARG_POINTER(profileName);
02333     
02334     nsCOMPtr<nsIFile> profileDir;
02335     nsresult rv = GetProfileDir(profileName, getter_AddRefs(profileDir));
02336     NS_ENSURE_SUCCESS(rv,rv);
02337 
02338     nsCOMPtr<nsIFile> newProfileDir;
02339     rv = profileDir->Clone(getter_AddRefs(newProfileDir));
02340     NS_ENSURE_SUCCESS(rv,rv);
02341 
02342     // The profile list used by GetOriginalProfileDir is the one with ALL 4.x
02343     // profiles - even ones for which there's a moz profile of the same name.
02344     nsCOMPtr<nsILocalFile> oldProfileDir;
02345     rv = GetOriginalProfileDir(profileName, getter_AddRefs(oldProfileDir));
02346     NS_ENSURE_SUCCESS(rv,rv);
02347 
02348     // In case of error, we'll restore what we've renamed.
02349     nsCAutoString origDirLeafName;
02350     rv = profileDir->GetNativeLeafName(origDirLeafName);
02351     NS_ENSURE_SUCCESS(rv,rv);
02352      
02353     // leave <xxxxxxxx>.slt alone, 
02354     // and remigrate the 4.x profile into <xxxxxxxx>.slt-new
02355     nsCAutoString newDirLeafName(origDirLeafName + NS_LITERAL_CSTRING("-new"));
02356     rv = newProfileDir->SetNativeLeafName(newDirLeafName);
02357     NS_ENSURE_SUCCESS(rv,rv);
02358     
02359     // Create a new directory for the remigrated profile
02360     rv = newProfileDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
02361     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create new directory for the remigrated profile");
02362     if (NS_SUCCEEDED(rv)) {
02363         rv = MigrateProfileInternal(profileName, oldProfileDir, newProfileDir);
02364         NS_ASSERTION(NS_SUCCEEDED(rv), "MigrateProfileInternal failed");
02365     }
02366     return rv;
02367 }
02368 
02369 nsresult
02370 nsProfile::ShowProfileWizard(void)
02371 {
02372     nsresult rv;
02373     nsCOMPtr<nsIWindowWatcher> windowWatcher(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
02374     if (NS_FAILED(rv)) return rv;
02375 
02376     nsCOMPtr<nsIDialogParamBlock> ioParamBlock(do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &rv));
02377     if (NS_FAILED(rv)) return rv;
02378     ioParamBlock->SetInt(0,4); // standard wizard buttons
02379    
02380     nsCOMPtr<nsIDOMWindow> newWindow;
02381     rv = windowWatcher->OpenWindow(nsnull,
02382                                    PROFILE_WIZARD_URL,
02383                                    "_blank",
02384                                    kDefaultOpenWindowParams,
02385                                    ioParamBlock,
02386                                    getter_AddRefs(newWindow));
02387     return rv;
02388 }
02389 
02390 NS_IMETHODIMP nsProfile::ProfileExists(const PRUnichar *profileName, PRBool *exists)
02391 {
02392     NS_ENSURE_ARG_POINTER(profileName); 
02393     NS_ENSURE_ARG_POINTER(exists);
02394 
02395     *exists = gProfileDataAccess->ProfileExists(profileName);
02396     return NS_OK;
02397 }
02398 
02399 NS_IMETHODIMP nsProfile::IsCurrentProfileAvailable(PRBool *available)
02400 {
02401     NS_ENSURE_ARG_POINTER(available);
02402 
02403     *available = mCurrentProfileAvailable;
02404     return NS_OK;
02405 }
02406 
02407 // Gets the number of unmigrated 4x profiles
02408 // Location: Common/Profiles
02409 NS_IMETHODIMP nsProfile::Get4xProfileCount(PRInt32 *numProfiles)
02410 {
02411     NS_ENSURE_ARG_POINTER(numProfiles);
02412 
02413     *numProfiles = 0;
02414 
02415     gProfileDataAccess->GetNum4xProfiles(numProfiles);
02416     return NS_OK;
02417 }
02418 
02419 
02420 // Migrates all unmigrated profiles
02421 NS_IMETHODIMP nsProfile::MigrateAllProfiles()
02422 {
02423     nsresult rv;
02424 
02425     PRUint32    numOldProfiles = 0;
02426     PRUnichar   **nameArray = nsnull;
02427     rv = GetProfileListX(nsIProfileInternal::LIST_ONLY_OLD, &numOldProfiles, &nameArray);
02428     if (NS_FAILED(rv)) return rv;
02429     for (PRUint32 i = 0; i < numOldProfiles; i++)
02430     {
02431         rv = MigrateProfile(nameArray[i]);
02432         if (NS_FAILED(rv)) break;
02433     }
02434     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numOldProfiles, nameArray);
02435     return rv;
02436 }
02437 
02438 
02439 NS_IMETHODIMP nsProfile::CloneProfile(const PRUnichar* newProfile)
02440 {
02441     NS_ENSURE_ARG_POINTER(newProfile);   
02442 
02443     nsresult rv = NS_OK;
02444 
02445 #if defined(DEBUG_profile)
02446     printf("ProfileManager : CloneProfile\n");
02447 #endif
02448     
02449     nsCOMPtr<nsIFile> currProfileDir;
02450     rv = GetCurrentProfileDir(getter_AddRefs(currProfileDir));
02451     if (NS_FAILED(rv)) return rv;
02452 
02453     PRBool exists;    
02454     rv = currProfileDir->Exists(&exists);
02455     if (NS_SUCCEEDED(rv) && exists)
02456     {
02457         nsCOMPtr<nsIFile> aFile;
02458         rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(aFile));
02459         if (NS_FAILED(rv)) return rv;
02460         nsCOMPtr<nsILocalFile> destDir(do_QueryInterface(aFile, &rv));
02461         if (NS_FAILED(rv)) return rv;
02462         destDir->AppendRelativePath(nsDependentString(newProfile));
02463 
02464         // Find a unique name in the dest dir
02465         rv = destDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
02466         if (NS_FAILED(rv)) return rv;
02467         
02468         rv = RecursiveCopy(currProfileDir, destDir);
02469         if (NS_FAILED(rv)) return rv;           
02470         rv = SetProfileDir(newProfile, destDir);
02471     }
02472 
02473 #if defined(DEBUG_profile_verbose)
02474     {
02475       if (NS_SUCCEEDED(rv))
02476       printf("ProfileManager : Cloned CurrentProfile\n");
02477 
02478       nsCAutoString temp; temp.AssignWithConversion(newProfile);
02479       printf("The new profile is ->%s<-\n", temp.get());
02480     }
02481 #endif
02482 
02483     gProfileDataAccess->mProfileDataChanged = PR_TRUE;
02484 
02485     return rv;
02486 }
02487 
02488 nsresult
02489 nsProfile::CreateDefaultProfile(void)
02490 {
02491     nsresult rv = NS_OK;
02492 
02493     // Get the default user profiles folder
02494     nsCOMPtr<nsIFile> profileRootDir;
02495     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(profileRootDir));
02496     if (NS_FAILED(rv)) return rv;
02497     
02498     nsAutoString profilePath;
02499     rv = profileRootDir->GetPath(profilePath);
02500     if (NS_FAILED(rv)) return rv;
02501 
02502     rv = CreateNewProfile(DEFAULT_PROFILE_NAME, profilePath.get(), nsnull, PR_TRUE);
02503 
02504     return rv;
02505 }
02506 
02507 NS_IMETHODIMP 
02508 nsProfile::UpdateRegistry(nsIFile* regName)
02509 {
02510    nsresult rv = NS_OK;
02511 
02512    gProfileDataAccess->mProfileDataChanged = PR_TRUE;
02513    rv= gProfileDataAccess->UpdateRegistry(regName);
02514 
02515    return rv;
02516 }
02517 
02518 NS_IMETHODIMP 
02519 nsProfile::SetRegStrings(const PRUnichar* profileName, 
02520                          const PRUnichar* regString,
02521                          const PRUnichar* regName,
02522                          const PRUnichar* regEmail,
02523                          const PRUnichar* regOption)
02524 {
02525    nsresult rv = NS_OK;
02526 
02527    ProfileStruct*    aProfile;
02528 
02529    rv = gProfileDataAccess->GetValue(profileName, &aProfile);
02530    if (NS_FAILED(rv)) return rv;
02531 
02532    if (aProfile == nsnull)
02533      return NS_ERROR_FAILURE;
02534    
02535    aProfile->NCHavePregInfo = regString;
02536 
02537    if (regName)    aProfile->NCProfileName   = regName;
02538    if (regEmail)   aProfile->NCEmailAddress  = regEmail;
02539    if (regOption)  aProfile->NCDeniedService = regOption;
02540 
02541    gProfileDataAccess->SetValue(aProfile);
02542 
02543    delete aProfile;
02544 
02545    return rv;
02546 }
02547 
02548 NS_IMETHODIMP 
02549 nsProfile::IsRegStringSet(const PRUnichar *profileName, char **regString)
02550 {
02551     NS_ENSURE_ARG_POINTER(profileName);   
02552     NS_ENSURE_ARG_POINTER(regString);
02553 
02554     gProfileDataAccess->CheckRegString(profileName, regString);
02555     return NS_OK;
02556 }
02557 
02558 /*
02559  * nsIProfileChangeStatus Implementation
02560  */
02561 
02562 NS_IMETHODIMP nsProfile::VetoChange()
02563 {
02564     mProfileChangeVetoed = PR_TRUE;
02565     return NS_OK;
02566 }
02567 
02568 NS_IMETHODIMP nsProfile::ChangeFailed()
02569 {
02570     mProfileChangeFailed = PR_TRUE;
02571     return NS_OK;
02572 }
02573 
02574 NS_IMETHODIMP
02575 nsProfile::GetRegStrings(const PRUnichar *aProfileName, 
02576                         PRUnichar **aRegString, 
02577                         PRUnichar **aRegName, 
02578                         PRUnichar **aRegEmail, 
02579                         PRUnichar **aRegOption)
02580 {
02581     NS_ENSURE_ARG_POINTER(aProfileName);
02582     NS_ENSURE_ARG_POINTER(aRegString);
02583     NS_ENSURE_ARG_POINTER(aRegName);
02584     NS_ENSURE_ARG_POINTER(aRegEmail);
02585     NS_ENSURE_ARG_POINTER(aRegOption);
02586 
02587     ProfileStruct*    profileVal;
02588 
02589     nsresult rv = gProfileDataAccess->GetValue(aProfileName, &profileVal);
02590     if (NS_FAILED(rv)) 
02591       return rv;
02592 
02593     if (profileVal == nsnull)
02594       return NS_ERROR_FAILURE;
02595 
02596     *aRegString = ToNewUnicode(profileVal->NCHavePregInfo);
02597     if (!*aRegString)
02598       return NS_ERROR_OUT_OF_MEMORY;    
02599 
02600     *aRegName = ToNewUnicode(profileVal->NCProfileName);
02601     if (!*aRegName)
02602       return NS_ERROR_OUT_OF_MEMORY;    
02603 
02604     *aRegEmail = ToNewUnicode(profileVal->NCEmailAddress);
02605     if (!*aRegEmail)
02606       return NS_ERROR_OUT_OF_MEMORY;    
02607 
02608     *aRegOption = ToNewUnicode(profileVal->NCDeniedService);
02609     if (!*aRegOption)
02610       return NS_ERROR_OUT_OF_MEMORY;    
02611 
02612      delete profileVal;
02613 
02614      return NS_OK;
02615 }
02616 
02617 nsresult nsProfile::GetLocalProfileDir(const PRUnichar* aProfileName,
02618                                        nsIFile** aLocalDir)
02619 {
02620   *aLocalDir = nsnull;
02621   nsresult rv;
02622   nsCOMPtr<nsIProperties> directoryService = 
02623     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
02624   if (NS_FAILED(rv))
02625     return rv;
02626   nsCOMPtr<nsIFile> localDir;
02627   rv = directoryService->Get(NS_APP_USER_PROFILES_LOCAL_ROOT_DIR,
02628                              NS_GET_IID(nsIFile),
02629                              getter_AddRefs(localDir));
02630   if (NS_FAILED(rv))
02631     return rv;
02632   rv = localDir->Append(nsDependentString(aProfileName));
02633   if (NS_FAILED(rv))
02634     return rv;
02635   localDir.swap(*aLocalDir);
02636   return NS_OK;
02637 }