Back to index

lightning-sunbird  0.9+nobinonly
nsProfileAccess.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsProfileAccess.h"
00041 #include "nsProfile.h"
00042 
00043 #include "pratom.h"
00044 #include "prmem.h"
00045 #include "plstr.h"
00046 #include "prenv.h"
00047 
00048 #include "nsIEnumerator.h"
00049 #include "prprf.h"
00050 #include "nsCOMPtr.h"
00051 #include "nsIComponentManager.h"
00052 #include "nsEscape.h"
00053 #include "nsDirectoryServiceDefs.h"
00054 #include "nsAppDirectoryServiceDefs.h"
00055 #include "nsILocalFile.h"
00056 #include "nsReadableUtils.h"
00057 #include "nsNativeCharsetUtils.h"
00058 
00059 #if defined(XP_MAC) || defined(XP_MACOSX)
00060 #include <Processes.h>
00061 #include <CFBundle.h>
00062 #include "nsILocalFileMac.h"
00063 #endif
00064 
00065 #ifdef XP_UNIX
00066 #include <unistd.h>
00067 #include <fcntl.h>
00068 #include <errno.h>
00069 #include <signal.h>
00070 #include "prnetdb.h"
00071 #include "prsystem.h"
00072 #endif
00073 
00074 #ifdef VMS
00075 #include <rmsdef.h>
00076 #endif
00077 
00078 #if defined (XP_UNIX)
00079 #define USER_ENVIRONMENT_VARIABLE "USER"
00080 #define LOGNAME_ENVIRONMENT_VARIABLE "LOGNAME"
00081 #define HOME_ENVIRONMENT_VARIABLE "HOME"
00082 #define PROFILE_NAME_ENVIRONMENT_VARIABLE "PROFILE_NAME"
00083 #define PROFILE_HOME_ENVIRONMENT_VARIABLE "PROFILE_HOME"
00084 #define DEFAULT_UNIX_PROFILE_NAME "default"
00085 #ifndef XP_MACOSX   /* Don't use symlink-based locking on OS X */
00086 #define USE_SYMLINK_LOCKING
00087 #endif
00088 #elif defined (XP_BEOS)
00089 #endif
00090 
00091 // Registry Keys
00092 
00093 #define kRegistryYesString (NS_LITERAL_STRING("yes"))
00094 #define kRegistryNoString (NS_LITERAL_STRING("no"))
00095 
00096 #define kRegistryProfileSubtreeString (NS_LITERAL_STRING("Profiles"))
00097 #define kRegistryCurrentProfileString (NS_LITERAL_STRING("CurrentProfile"))
00098 #define kRegistryNCServiceDenialString (NS_LITERAL_STRING("NCServiceDenial"))
00099 #define kRegistryNCProfileNameString (NS_LITERAL_STRING("NCProfileName"))
00100 #define kRegistryNCUserEmailString (NS_LITERAL_STRING("NCEmailAddress"))
00101 #define kRegistryNCHavePREGInfoString (NS_LITERAL_STRING("NCHavePregInfo"))
00102 #define kRegistryHavePREGInfoString (NS_LITERAL_STRING("HavePregInfo"))
00103 #define kRegistryMigratedString (NS_LITERAL_STRING("migrated"))
00104 #define kRegistryDirectoryString (NS_LITERAL_STRING("directory"))
00105 #define kRegistryNeedMigrationString (NS_LITERAL_STRING("NeedMigration"))
00106 #define kRegistryMozRegDataMovedString (NS_LITERAL_STRING("OldRegDataMoved"))
00107 #define kRegistryCreationTimeString (NS_LITERAL_CSTRING("CreationTime"))
00108 #define kRegistryLastModTimeString (NS_LITERAL_CSTRING("LastModTime"))
00109 #define kRegistryMigratedFromString (NS_LITERAL_CSTRING("MigFromDir"))
00110 #define kRegistryVersionString (NS_LITERAL_STRING("Version"))
00111 #define kRegistryVersion_1_0 (NS_LITERAL_STRING("1.0"))
00112 #define kRegistryCurrentVersion (NS_LITERAL_STRING("1.0"))
00113 #define kRegistryStartWithLastString (NS_LITERAL_CSTRING("AutoStartWithLast"))
00114 
00115 // **********************************************************************
00116 // class nsProfileAccess
00117 // **********************************************************************
00118 
00119 /*
00120  * Constructor/Destructor
00121  * FillProfileInfo reads the registry and fills profileStructs
00122  */
00123 nsProfileAccess::nsProfileAccess()
00124 {
00125     mProfileDataChanged  =  PR_FALSE;
00126     mForgetProfileCalled =  PR_FALSE;
00127     m4xProfilesAdded     =  PR_FALSE;
00128     mStartWithLastProfile = PR_FALSE;
00129     mProfiles            =  new nsVoidArray();
00130 
00131     // Get the profile registry path
00132     NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_FILE, getter_AddRefs(mNewRegFile));
00133 
00134     // Read the data into internal data structure....
00135     FillProfileInfo(mNewRegFile);
00136 }
00137 
00138 // On the way out, close the registry if it is
00139 // still opened and free up the resources.
00140 nsProfileAccess::~nsProfileAccess()
00141 {
00142     // Release all resources.
00143     mNewRegFile = nsnull;
00144     FreeProfileMembers(mProfiles);
00145 }
00146 
00147 // Free up the member profile structs
00148 void
00149 nsProfileAccess::FreeProfileMembers(nsVoidArray *profiles)
00150 {
00151     NS_ASSERTION(profiles, "Invalid profiles");
00152 
00153     PRInt32 index = 0;
00154     PRInt32 numElems = profiles->Count();
00155 
00156     ProfileStruct* aProfile;
00157     if (profiles) {
00158         for (index = 0; index < numElems; index++)
00159         {
00160             aProfile = (ProfileStruct *) profiles->ElementAt(index);
00161 
00162             delete aProfile;
00163         }
00164 
00165         delete profiles;
00166     }
00167 }
00168 
00169 
00170 // Given the name of the profile, the structure that
00171 // contains the relavant profile information will be filled.
00172 // Caller must free up the profile struct.
00173 nsresult
00174 nsProfileAccess::GetValue(const PRUnichar* profileName, ProfileStruct** aProfile)
00175 {
00176     NS_ENSURE_ARG(profileName);
00177     NS_ENSURE_ARG_POINTER(aProfile);
00178     *aProfile = nsnull;
00179 
00180     PRInt32 index = 0;
00181     index = FindProfileIndex(profileName, PR_FALSE);
00182     if (index < 0)
00183         return NS_ERROR_FAILURE;
00184 
00185     ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00186 
00187     *aProfile = new ProfileStruct(*profileItem);
00188     if (!*aProfile)
00189         return NS_ERROR_OUT_OF_MEMORY;
00190 
00191     return NS_OK;
00192 }
00193 
00194 // This method writes all changes to the array of the
00195 // profile structs. If it is an existing profile, it
00196 // will be updated. If it is a new profile, it gets added
00197 // to the list.
00198 nsresult
00199 nsProfileAccess::SetValue(ProfileStruct* aProfile)
00200 {
00201     NS_ENSURE_ARG(aProfile);
00202 
00203     PRInt32     index = 0;
00204     ProfileStruct* profileItem;
00205 
00206     index = FindProfileIndex(aProfile->profileName.get(), aProfile->isImportType);
00207 
00208     if (index >= 0)
00209     {
00210         profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00211         *profileItem = *aProfile;
00212         profileItem->updateProfileEntry = PR_TRUE;
00213     }
00214     else
00215     {
00216         profileItem     = new ProfileStruct(*aProfile);
00217         if (!profileItem)
00218             return NS_ERROR_OUT_OF_MEMORY;
00219     profileItem->updateProfileEntry = PR_TRUE;
00220 
00221         if (!mProfiles) {
00222             mProfiles = new nsVoidArray;
00223         if (!mProfiles)
00224                 return NS_ERROR_OUT_OF_MEMORY;
00225         }
00226         mProfiles->AppendElement((void*)profileItem);
00227     }
00228 
00229     return NS_OK;
00230 }
00231 
00232 // Enumerates through the registry for profile
00233 // information. Reads in the data into the array
00234 // of profile structs. After this, all the callers
00235 // requesting profile info will get thier data from
00236 // profiles array. All the udates will be done to this
00237 // data structure to reflect the latest status.
00238 // Data will be flushed at the end.
00239 nsresult
00240 nsProfileAccess::FillProfileInfo(nsIFile* regName)
00241 {
00242     nsresult rv = NS_OK;
00243 
00244     nsCOMPtr<nsIRegistry> registry(do_CreateInstance(NS_REGISTRY_CONTRACTID, &rv));
00245     if (NS_FAILED(rv)) return rv;
00246     rv = registry->Open(regName);
00247     if (NS_FAILED(rv)) return rv;
00248 
00249     // Enumerate all subkeys (immediately) under the given node.
00250     nsCOMPtr<nsIEnumerator> enumKeys;
00251     nsRegistryKey profilesTreeKey;
00252 
00253     rv = registry->GetKey(nsIRegistry::Common,
00254                             kRegistryProfileSubtreeString.get(),
00255                             &profilesTreeKey);
00256 
00257     if (NS_FAILED(rv))
00258     {
00259         rv = registry->AddKey(nsIRegistry::Common,
00260                                 kRegistryProfileSubtreeString.get(),
00261                                 &profilesTreeKey);
00262         if (NS_FAILED(rv)) return rv;
00263     }
00264 
00265 
00266     // introducing these tmp variables as nsString variables cannot be passed to
00267     // the resgitry methods
00268     nsXPIDLString tmpCurrentProfile;
00269     nsXPIDLString tmpVersion;
00270     nsXPIDLString tmpPREGInfo;
00271 
00272 
00273     // For the following variables, we do not check for the rv value
00274     // but check for the variable instead, because it is valid to proceed
00275     // without the variables having a value. That's why there are no returns
00276     // for invalid rv values.
00277 
00278     // Get the current profile
00279     rv = registry->GetString(profilesTreeKey,
00280                                kRegistryCurrentProfileString.get(),
00281                                getter_Copies(tmpCurrentProfile));
00282 
00283     if (tmpCurrentProfile)
00284     {
00285         // If current profile does not exist, mCurrentProfile will not be set
00286         // This is not harmful, as GetCurrentProfile method needs to return this value
00287         // And GetCurrentProfile returns:
00288         //    the current profile if set
00289         //    the first profile if profiles exist but no current profile is set
00290         //    an empty string if no profiles exist.
00291 
00292         mCurrentProfile = NS_STATIC_CAST(const PRUnichar*, tmpCurrentProfile);
00293     }
00294 
00295     // Get the profile version
00296     rv = registry->GetString(profilesTreeKey,
00297                              kRegistryVersionString.get(),
00298                              getter_Copies(tmpVersion));
00299 
00300     // Get the preg info
00301     rv = registry->GetString(profilesTreeKey,
00302                              kRegistryHavePREGInfoString.get(),
00303                              getter_Copies(tmpPREGInfo));
00304 
00305     if (tmpPREGInfo == nsnull)
00306     {
00307         mHavePREGInfo = kRegistryNoString;
00308         mProfileDataChanged = PR_TRUE;
00309     }
00310     
00311     // Get the StartWithLastProfile flag
00312     PRInt32 tempLong;
00313     rv = registry->GetInt(profilesTreeKey,
00314                            kRegistryStartWithLastString.get(),
00315                            &tempLong);
00316     if (NS_SUCCEEDED(rv))
00317         mStartWithLastProfile = tempLong;
00318 
00319     rv = registry->EnumerateSubtrees( profilesTreeKey, getter_AddRefs(enumKeys));
00320     if (NS_FAILED(rv)) return rv;
00321 
00322     rv = enumKeys->First();
00323     if (NS_FAILED(rv)) return rv;
00324 
00325     PRBool currentProfileValid = mCurrentProfile.IsEmpty();
00326 
00327     while (NS_OK != enumKeys->IsDone())
00328     {
00329         nsCOMPtr<nsISupports> base;
00330 
00331         rv = enumKeys->CurrentItem( getter_AddRefs(base) );
00332         if (NS_FAILED(rv)) return rv;
00333 
00334         // Get specific interface.
00335         nsCOMPtr <nsIRegistryNode> node;
00336         nsIID nodeIID = NS_IREGISTRYNODE_IID;
00337 
00338         rv = base->QueryInterface( nodeIID, getter_AddRefs(node));
00339         if (NS_FAILED(rv)) return rv;
00340 
00341         // Get node name.
00342         nsXPIDLString profile;
00343         nsXPIDLString isMigrated;
00344         nsXPIDLString NCProfileName;
00345         nsXPIDLString NCDeniedService;
00346         nsXPIDLString NCEmailAddress;
00347         nsXPIDLString NCHavePregInfo;
00348 
00349         rv = node->GetName(getter_Copies(profile));
00350         if (NS_FAILED(rv)) return rv;
00351 
00352         nsRegistryKey profKey;
00353         rv = node->GetKey(&profKey);
00354         if (NS_FAILED(rv)) return rv;
00355 
00356         rv = registry->GetString(profKey,
00357                                  kRegistryMigratedString.get(),
00358                                  getter_Copies(isMigrated));
00359         if (NS_FAILED(rv)) return rv;
00360         nsDependentString isMigratedString(isMigrated);
00361 
00362         // Not checking the return values of these variables as they
00363         // are for activation, they are optional and their values
00364         // do not call for a return
00365         registry->GetString(profKey,
00366                             kRegistryNCProfileNameString.get(),
00367                             getter_Copies(NCProfileName));
00368 
00369         registry->GetString(profKey,
00370                             kRegistryNCServiceDenialString.get(),
00371                             getter_Copies(NCDeniedService));
00372 
00373         registry->GetString(profKey,
00374                             kRegistryNCUserEmailString.get(),
00375                             getter_Copies(NCEmailAddress));
00376 
00377         registry->GetString(profKey,
00378                             kRegistryNCHavePREGInfoString.get(),
00379                             getter_Copies(NCHavePregInfo));
00380 
00381         // Make sure that mCurrentProfile is valid
00382         if (!mCurrentProfile.IsEmpty() && mCurrentProfile.Equals(profile))
00383           currentProfileValid = PR_TRUE;
00384 
00385         ProfileStruct*  profileItem     = new ProfileStruct();
00386         if (!profileItem)
00387             return NS_ERROR_OUT_OF_MEMORY;
00388 
00389         profileItem->updateProfileEntry     = PR_TRUE;
00390         profileItem->profileName      = NS_STATIC_CAST(const PRUnichar*, profile);
00391 
00392         PRInt64 tmpLongLong;
00393         rv = registry->GetLongLong(profKey,
00394                                    kRegistryCreationTimeString.get(),
00395                                    &tmpLongLong);
00396         if (NS_SUCCEEDED(rv))
00397             profileItem->creationTime = tmpLongLong;
00398 
00399         rv = registry->GetLongLong(profKey,
00400                                    kRegistryLastModTimeString.get(),
00401                                    &tmpLongLong);
00402         if (NS_SUCCEEDED(rv))
00403             profileItem->lastModTime = tmpLongLong;
00404 
00405         rv = profileItem->InternalizeLocation(registry, profKey, PR_FALSE);
00406         NS_ASSERTION(NS_SUCCEEDED(rv), "Internalizing profile location failed");
00407         // Not checking the error since most won't have this info
00408         profileItem->InternalizeMigratedFromLocation(registry, profKey);
00409 
00410         profileItem->isMigrated       = isMigratedString.Equals(kRegistryYesString);
00411 
00412         if (NCProfileName)
00413             profileItem->NCProfileName = NS_STATIC_CAST(const PRUnichar*, NCProfileName);
00414 
00415         if (NCDeniedService)
00416             profileItem->NCDeniedService = NS_STATIC_CAST(const PRUnichar*, NCDeniedService);
00417 
00418         if (NCEmailAddress)
00419             profileItem->NCEmailAddress = NS_STATIC_CAST(const PRUnichar*, NCEmailAddress);
00420 
00421         if (NCHavePregInfo)
00422             profileItem->NCHavePregInfo = NS_STATIC_CAST(const PRUnichar*, NCHavePregInfo);
00423 
00424         profileItem->isImportType = PR_FALSE;
00425         if (!mProfiles) {
00426             mProfiles = new nsVoidArray();
00427 
00428             if (!mProfiles) {
00429                 delete profileItem;
00430                 return NS_ERROR_OUT_OF_MEMORY;
00431             }
00432         }
00433 
00434         mProfiles->AppendElement((void*)profileItem);
00435 
00436         rv = enumKeys->Next();
00437         if (NS_FAILED(rv)) return rv;
00438     }
00439 
00440     if (!currentProfileValid)
00441       mCurrentProfile.SetLength(0);
00442 
00443     return rv;
00444 }
00445 
00446 // Return the number of 5x profiles.
00447 void
00448 nsProfileAccess::GetNumProfiles(PRInt32 *numProfiles)
00449 {
00450     if (!numProfiles) {
00451         NS_ASSERTION(PR_FALSE, "invalid argument");
00452         return;
00453     }
00454 
00455     PRInt32 index, numElems = mProfiles->Count();
00456 
00457     *numProfiles = 0;
00458 
00459     for(index = 0; index < numElems; index++)
00460     {
00461         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00462 
00463         if (profileItem->isMigrated && !profileItem->isImportType)
00464         {
00465             (*numProfiles)++;
00466         }
00467     }
00468 }
00469 
00470 // Return the number of 4x (>=4.5 & < 5.0) profiles.
00471 void
00472 nsProfileAccess::GetNum4xProfiles(PRInt32 *numProfiles)
00473 {
00474     if (!numProfiles) {
00475         NS_ASSERTION(PR_FALSE, "invalid argument");
00476         return;
00477     }
00478 
00479     PRInt32 index, numElems = mProfiles->Count();
00480 
00481     *numProfiles = 0;
00482 
00483     for(index = 0; index < numElems; index++)
00484     {
00485         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00486 
00487         if (!profileItem->isMigrated && !profileItem->isImportType)
00488         {
00489             (*numProfiles)++;
00490         }
00491     }
00492 }
00493 
00494 // If the application can't find the current profile,
00495 // the first profile will be used as the current profile.
00496 // This routine returns the first 5x profile.
00497 // Caller must free up the string (firstProfile).
00498 void
00499 nsProfileAccess::GetFirstProfile(PRUnichar **firstProfile)
00500 {
00501     if (!firstProfile) {
00502         NS_ASSERTION(PR_FALSE, "Invalid firstProfile pointer");
00503         return;
00504     }
00505 
00506     PRInt32 index, numElems = mProfiles->Count();
00507 
00508     *firstProfile = nsnull;
00509 
00510     for(index = 0; index < numElems; index++)
00511     {
00512         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00513 
00514         if (profileItem->isMigrated && !profileItem->isImportType)
00515         {
00516             *firstProfile = ToNewUnicode(profileItem->profileName);
00517             break;
00518         }
00519     }
00520 }
00521 
00522 // Set the current profile. Opearting directly on the tree.
00523 // A separate struct should be maintained for the top level info.
00524 // That way we can eliminate additional registry access. For
00525 // now, we depend on registry operations.
00526 // Capture the current profile information into mCurrentProfile.
00527 void
00528 nsProfileAccess::SetCurrentProfile(const PRUnichar *profileName)
00529 {
00530     NS_ASSERTION(profileName, "Invalid profile name");
00531 
00532     mCurrentProfile = profileName;
00533     mProfileDataChanged = PR_TRUE;
00534 }
00535 
00536 // Return the current profile value.
00537 // If mCurrent profile is already set, that value is returned.
00538 // If there is only one profile that value is set to CurrentProfile.
00539 void
00540 nsProfileAccess::GetCurrentProfile(PRUnichar **profileName)
00541 {
00542     *profileName = nsnull;
00543 
00544     if (!mCurrentProfile.IsEmpty() || mForgetProfileCalled)
00545     {
00546         *profileName = ToNewUnicode(mCurrentProfile);
00547     }
00548 
00549     // If there are profiles and profileName is not
00550     // set yet. Get the first one and set it as Current Profile.
00551     if (*profileName == nsnull)
00552     {
00553         GetFirstProfile(profileName); // We might not have any
00554         if (*profileName)
00555             SetCurrentProfile(*profileName);
00556     }
00557 }
00558 
00559 // Delete a profile from profile structs
00560 void
00561 nsProfileAccess::RemoveSubTree(const PRUnichar* profileName)
00562 {
00563     NS_ASSERTION(profileName, "Invalid profile name");
00564 
00565     // delete this entry from the mProfiles array
00566     PRInt32     index = FindProfileIndex(profileName, PR_FALSE);
00567 
00568     if (index >= 0)
00569     {
00570         mProfiles->RemoveElementAt(index);
00571 
00572         if (mCurrentProfile.Equals(profileName))
00573         {
00574             mCurrentProfile.SetLength(0);
00575         }
00576     }
00577 }
00578 
00579 // Return the index of a given profiel from the arraf of profile structs.
00580 PRInt32
00581 nsProfileAccess::FindProfileIndex(const PRUnichar* profileName, PRBool forImport)
00582 {
00583     NS_ASSERTION(profileName, "Invalid profile name");
00584 
00585     PRInt32 retval = -1;
00586     PRInt32 index, numElems = mProfiles->Count();
00587 
00588     for (index=0; index < numElems; index++)
00589     {
00590         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00591 
00592         if(profileItem->profileName.Equals(profileName) && (profileItem->isImportType == forImport))
00593         {
00594             retval = index;
00595             break;
00596         }
00597     }
00598     return retval;
00599 }
00600 
00601 // Flush profile information from the data structure to the registry.
00602 nsresult
00603 nsProfileAccess::UpdateRegistry(nsIFile* regName)
00604 {
00605     nsresult rv;
00606 
00607     if (!mProfileDataChanged)
00608     {
00609         return NS_OK;
00610     }
00611 
00612     if (!regName)
00613     {
00614         regName = mNewRegFile;
00615     }
00616 
00617     nsCOMPtr<nsIRegistry> registry(do_CreateInstance(NS_REGISTRY_CONTRACTID, &rv));
00618     if (NS_FAILED(rv)) return rv;
00619     rv = registry->Open(regName);
00620     if (NS_FAILED(rv)) return rv;
00621 
00622     // Enumerate all subkeys (immediately) under the given node.
00623     nsCOMPtr<nsIEnumerator> enumKeys;
00624     nsRegistryKey profilesTreeKey;
00625 
00626     // Get the major subtree
00627     rv = registry->GetKey(nsIRegistry::Common,
00628                           kRegistryProfileSubtreeString.get(),
00629                           &profilesTreeKey);
00630     if (NS_FAILED(rv))
00631     {
00632         rv = registry->AddKey(nsIRegistry::Common,
00633                                 kRegistryProfileSubtreeString.get(),
00634                                 &profilesTreeKey);
00635         if (NS_FAILED(rv)) return rv;
00636     }
00637 
00638     // Set the current profile
00639     if (!mCurrentProfile.IsEmpty()) {
00640 
00641         rv = registry->SetString(profilesTreeKey,
00642                                  kRegistryCurrentProfileString.get(),
00643                                  mCurrentProfile.get());
00644         if (NS_FAILED(rv)) return rv;
00645     }
00646 
00647     // Set the registry version
00648     rv = registry->SetString(profilesTreeKey,
00649                              kRegistryVersionString.get(),
00650                              kRegistryCurrentVersion.get());
00651     if (NS_FAILED(rv)) return rv;
00652 
00653     // Set preg info
00654     rv = registry->SetString(profilesTreeKey,
00655                              kRegistryHavePREGInfoString.get(),
00656                              mHavePREGInfo.get());
00657     if (NS_FAILED(rv)) return rv;
00658 
00659     // Set the StartWithLastProfile flag
00660     rv = registry->SetInt(profilesTreeKey,
00661                           kRegistryStartWithLastString.get(),
00662                           mStartWithLastProfile);
00663     if (NS_FAILED(rv)) return rv;
00664 
00665     rv = registry->EnumerateSubtrees(profilesTreeKey, getter_AddRefs(enumKeys));
00666     if (NS_FAILED(rv)) return rv;
00667 
00668     rv = enumKeys->First();
00669     if (NS_FAILED(rv)) return rv;
00670 
00671     while (NS_OK != enumKeys->IsDone())
00672     {
00673         nsCOMPtr<nsISupports> base;
00674 
00675         rv = enumKeys->CurrentItem( getter_AddRefs(base) );
00676         if (NS_FAILED(rv)) return rv;
00677 
00678         // Get specific interface.
00679         nsCOMPtr <nsIRegistryNode> node;
00680         nsIID nodeIID = NS_IREGISTRYNODE_IID;
00681 
00682         rv = base->QueryInterface( nodeIID, getter_AddRefs(node));
00683         if (NS_FAILED(rv)) return rv;
00684 
00685         // Get node name.
00686         nsXPIDLString profile;
00687         nsXPIDLString isMigrated;
00688         nsXPIDLString directory;
00689 
00690         rv = node->GetName( getter_Copies(profile) );
00691         if (NS_FAILED(rv)) return rv;
00692 
00693         PRInt32 index = 0;
00694 
00695         index = FindProfileIndex(profile, PR_FALSE);
00696 
00697         if (index < 0)
00698         {
00699             // This profile is deleted.
00700             rv = registry->RemoveKey(profilesTreeKey, profile);
00701             if (NS_FAILED(rv)) return rv;
00702         }
00703         else
00704         {
00705             nsRegistryKey profKey;
00706 
00707             ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00708 
00709             rv = node->GetKey(&profKey);
00710             if (NS_FAILED(rv)) return rv;
00711 
00712             rv = registry->SetString(profKey,
00713                                      kRegistryMigratedString.get(),
00714                                      profileItem->isMigrated ? kRegistryYesString.get() : kRegistryNoString.get());
00715             if (NS_FAILED(rv)) return rv;
00716 
00717             registry->SetString(profKey,
00718                                 kRegistryNCProfileNameString.get(),
00719                                 profileItem->NCProfileName.get());
00720 
00721             registry->SetString(profKey,
00722                                 kRegistryNCServiceDenialString.get(),
00723                                 profileItem->NCDeniedService.get());
00724 
00725             registry->SetString(profKey,
00726                                 kRegistryNCUserEmailString.get(),
00727                                 profileItem->NCEmailAddress.get());
00728 
00729             registry->SetString(profKey,
00730                                 kRegistryNCHavePREGInfoString.get(),
00731                                 profileItem->NCHavePregInfo.get());
00732 
00733             registry->SetLongLong(profKey,
00734                                   kRegistryCreationTimeString.get(),
00735                                   &profileItem->creationTime);
00736 
00737             registry->SetLongLong(profKey,
00738                                   kRegistryLastModTimeString.get(),
00739                                   &profileItem->lastModTime);
00740 
00741             rv = profileItem->ExternalizeLocation(registry, profKey);
00742             if (NS_FAILED(rv)) {
00743                 NS_ASSERTION(PR_FALSE, "Could not update profile location");
00744                 rv = enumKeys->Next();
00745                 if (NS_FAILED(rv)) return rv;
00746                 continue;
00747             }
00748             profileItem->ExternalizeMigratedFromLocation(registry, profKey);
00749 
00750             profileItem->updateProfileEntry = PR_FALSE;
00751         }
00752         rv = enumKeys->Next();
00753         if (NS_FAILED(rv)) return rv;
00754     }
00755 
00756     // Take care of new nodes
00757     PRInt32 numElems = mProfiles->Count();
00758     for (int i = 0; i < numElems; i++)
00759     {
00760         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(i));
00761 
00762         if (!profileItem->isImportType && profileItem->updateProfileEntry)
00763         {
00764             nsRegistryKey profKey;
00765 
00766             rv = registry->AddKey(profilesTreeKey,
00767                                     profileItem->profileName.get(),
00768                                     &profKey);
00769             if (NS_FAILED(rv)) return rv;
00770 
00771             rv = registry->SetString(profKey,
00772                                      kRegistryMigratedString.get(),
00773                                      profileItem->isMigrated ? kRegistryYesString.get() : kRegistryNoString.get());
00774             if (NS_FAILED(rv)) return rv;
00775 
00776             registry->SetString(profKey,
00777                                 kRegistryNCProfileNameString.get(),
00778                                 profileItem->NCProfileName.get());
00779 
00780             registry->SetString(profKey,
00781                                 kRegistryNCServiceDenialString.get(),
00782                                 profileItem->NCDeniedService.get());
00783 
00784             registry->SetString(profKey,
00785                                 kRegistryNCUserEmailString.get(),
00786                                 profileItem->NCEmailAddress.get());
00787 
00788             registry->SetString(profKey,
00789                                 kRegistryNCHavePREGInfoString.get(),
00790                                 profileItem->NCHavePregInfo.get());
00791 
00792             registry->SetLongLong(profKey,
00793                                   kRegistryCreationTimeString.get(),
00794                                   &profileItem->creationTime);
00795 
00796             registry->SetLongLong(profKey,
00797                                   kRegistryLastModTimeString.get(),
00798                                   &profileItem->lastModTime);
00799 
00800             rv = profileItem->ExternalizeLocation(registry, profKey);
00801             if (NS_FAILED(rv)) {
00802                 NS_ASSERTION(PR_FALSE, "Could not update profile location");
00803                 continue;
00804             }
00805             profileItem->ExternalizeMigratedFromLocation(registry, profKey);
00806 
00807             profileItem->updateProfileEntry = PR_FALSE;
00808         }
00809     }
00810 
00811     mProfileDataChanged = PR_FALSE;
00812 
00813     return rv;
00814 }
00815 
00816 nsresult
00817 nsProfileAccess::GetOriginalProfileDir(const PRUnichar *profileName, nsILocalFile **originalDir)
00818 {
00819     NS_ENSURE_ARG(profileName);
00820     NS_ENSURE_ARG_POINTER(originalDir);
00821     *originalDir = nsnull;
00822     nsresult rv = NS_OK;
00823 
00824     PRInt32 index = FindProfileIndex(profileName, PR_TRUE);
00825     if (index >= 0)
00826     {
00827         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00828         nsCOMPtr<nsILocalFile> profileDir;
00829         rv = profileItem->GetResolvedProfileDir(getter_AddRefs(profileDir));
00830         if (NS_SUCCEEDED(rv) && profileDir)
00831         {
00832 #ifdef XP_MAC
00833             PRBool exists;
00834             rv = profileDir->Exists(&exists);
00835             if (NS_FAILED(rv))
00836                 return rv;
00837             if (exists) {
00838                 PRBool inTrash;
00839                 nsCOMPtr<nsIFile> trashFolder;
00840 
00841                 rv = NS_GetSpecialDirectory(NS_MAC_TRASH_DIR, getter_AddRefs(trashFolder));
00842                 if (NS_FAILED(rv)) return rv;
00843                 rv = trashFolder->Contains(profileDir, PR_TRUE, &inTrash);
00844                 if (NS_FAILED(rv)) return rv;
00845                 if (inTrash) {
00846                     return NS_ERROR_FILE_NOT_FOUND;
00847                 }
00848             }
00849 #endif
00850             NS_IF_ADDREF(*originalDir = profileDir);
00851         }
00852         return rv;
00853     }
00854     return NS_ERROR_FAILURE;
00855 }
00856 
00857 nsresult
00858 nsProfileAccess::SetMigratedFromDir(const PRUnichar *profileName, nsILocalFile *originalDir)
00859 {
00860     NS_ENSURE_ARG(profileName);
00861     NS_ENSURE_ARG(originalDir);
00862 
00863     PRInt32 index = FindProfileIndex(profileName, PR_FALSE);
00864     if (index >= 0)
00865     {
00866         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00867         profileItem->migratedFrom = originalDir;
00868         profileItem->updateProfileEntry = PR_TRUE;
00869         return NS_OK;
00870     }
00871     return NS_ERROR_FAILURE;
00872 }
00873 
00874 nsresult
00875 nsProfileAccess::SetProfileLastModTime(const PRUnichar *profileName, PRInt64 lastModTime)
00876 {
00877     NS_ENSURE_ARG(profileName);
00878 
00879     PRInt32 index = FindProfileIndex(profileName, PR_FALSE);
00880     if (index >= 0)
00881     {
00882         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00883         profileItem->lastModTime = lastModTime;
00884         profileItem->updateProfileEntry = PR_TRUE;
00885         return NS_OK;
00886     }
00887     return NS_ERROR_FAILURE;
00888 }
00889 
00890 nsresult
00891 nsProfileAccess::GetStartWithLastUsedProfile(PRBool *aStartWithLastUsedProfile)
00892 {
00893     NS_ENSURE_ARG_POINTER(aStartWithLastUsedProfile);
00894     *aStartWithLastUsedProfile = mStartWithLastProfile;
00895     return NS_OK;
00896 }
00897 
00898 nsresult
00899 nsProfileAccess::SetStartWithLastUsedProfile(PRBool aStartWithLastUsedProfile)
00900 {
00901     mStartWithLastProfile = aStartWithLastUsedProfile;
00902     mProfileDataChanged = PR_TRUE;
00903     return NS_OK;
00904 }
00905 
00906 // Return the list of profiles, 4x, 5x, or both.
00907 nsresult
00908 nsProfileAccess::GetProfileList(PRInt32 whichKind, PRUint32 *length, PRUnichar ***result)
00909 {
00910     NS_ENSURE_ARG_POINTER(length);
00911     *length = 0;
00912     NS_ENSURE_ARG_POINTER(result);
00913     *result = nsnull;
00914 
00915     nsresult rv = NS_OK;
00916     PRInt32 count, localLength = 0;
00917     PRUnichar **outArray, **next;
00918     PRInt32 numElems = mProfiles->Count();
00919     PRInt32 profilesCount;
00920 
00921     switch (whichKind)
00922     {
00923         case nsIProfileInternal::LIST_ONLY_NEW:
00924             GetNumProfiles(&count);
00925             break;
00926         case nsIProfileInternal::LIST_ONLY_OLD:
00927             GetNum4xProfiles(&count);
00928             break;
00929         case nsIProfileInternal::LIST_ALL:
00930             GetNum4xProfiles(&count);
00931             GetNumProfiles(&profilesCount);
00932             count += profilesCount;
00933             break;
00934         case nsIProfileInternal::LIST_FOR_IMPORT:
00935             GetNum4xProfiles(&count);
00936             GetNumProfiles(&profilesCount);
00937             count = numElems - (count + profilesCount);
00938             break;
00939         default:
00940             NS_ASSERTION(PR_FALSE, "Bad parameter");
00941             return NS_ERROR_INVALID_ARG;
00942     }
00943 
00944     next = outArray = (PRUnichar **)nsMemory::Alloc(count * sizeof(PRUnichar *));
00945     if (!outArray)
00946         return NS_ERROR_OUT_OF_MEMORY;
00947 
00948     for (PRInt32 index=0; index < numElems && localLength < count; index++)
00949     {
00950         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00951 
00952         if (whichKind == nsIProfileInternal::LIST_ONLY_OLD && (profileItem->isMigrated || profileItem->isImportType))
00953             continue;
00954         else if (whichKind == nsIProfileInternal::LIST_ONLY_NEW && (!profileItem->isMigrated || profileItem->isImportType))
00955             continue;
00956         else if (whichKind == nsIProfileInternal::LIST_ALL && profileItem->isImportType)
00957             continue;
00958         else if (whichKind == nsIProfileInternal::LIST_FOR_IMPORT && !profileItem->isImportType)
00959             continue;
00960         *next = ToNewUnicode(profileItem->profileName);
00961         if (*next == nsnull)
00962         {
00963             rv = NS_ERROR_OUT_OF_MEMORY;
00964             break;
00965         }
00966         next++;
00967         localLength++;
00968     }
00969 
00970     if (NS_SUCCEEDED(rv))
00971     {
00972         *result = outArray;
00973         *length = localLength;
00974     }
00975     else
00976     {
00977         while (--next >= outArray)
00978             nsMemory::Free(*next);
00979         nsMemory::Free(outArray);
00980     }
00981 
00982     return rv;
00983 }
00984 
00985 // Return a boolean based on the profile existence.
00986 PRBool
00987 nsProfileAccess::ProfileExists(const PRUnichar *profileName)
00988 {
00989     NS_ASSERTION(profileName, "Invalid profile name");
00990 
00991     PRBool exists = PR_FALSE;
00992     PRInt32 numElems = mProfiles->Count();
00993 
00994     for (PRInt32 index=0; index < numElems; index++)
00995     {
00996         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
00997         if (!profileItem->isImportType && profileItem->profileName.Equals(profileName))
00998         {
00999             exists = PR_TRUE;
01000             break;
01001         }
01002     }
01003     return exists;
01004 }
01005 
01006 // Capture the 4x profile information from the old registry (4x)
01007 nsresult
01008 nsProfileAccess::Get4xProfileInfo(nsIFile *registryFile, PRBool fromImport)
01009 {
01010     nsresult rv = NS_OK;
01011     if (fromImport && m4xProfilesAdded)
01012         return rv;
01013 
01014 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_MAC) || defined(XP_MACOSX)
01015     NS_ENSURE_ARG(registryFile);
01016 
01017     nsCOMPtr<nsIRegistry> oldReg(do_CreateInstance(NS_REGISTRY_CONTRACTID, &rv));
01018     if (NS_FAILED(rv)) return rv;
01019     rv = oldReg->Open(registryFile);
01020     if (NS_FAILED(rv)) return rv;
01021 
01022     // Enumerate 4x tree and create an array of that information.
01023     // Enumerate all subkeys (immediately) under the given node.
01024     nsCOMPtr<nsIEnumerator> enumKeys;
01025 
01026     rv = oldReg->EnumerateSubtrees(nsIRegistry::Users,
01027                                    getter_AddRefs(enumKeys));
01028     if (NS_FAILED(rv)) return rv;
01029 
01030     rv = enumKeys->First();
01031     if (NS_FAILED(rv)) return rv;
01032 
01033     if (fromImport)
01034         m4xProfilesAdded = PR_TRUE;
01035     // Enumerate subkeys till done.
01036     while( (NS_OK != enumKeys->IsDone()))
01037     {
01038         nsCOMPtr<nsISupports> base;
01039         rv = enumKeys->CurrentItem(getter_AddRefs(base));
01040         if (NS_FAILED(rv)) return rv;
01041 
01042         // Get specific interface.
01043         nsCOMPtr <nsIRegistryNode> node;
01044         nsIID nodeIID = NS_IREGISTRYNODE_IID;
01045         rv = base->QueryInterface( nodeIID, getter_AddRefs(node));
01046         if (NS_FAILED(rv)) return rv;
01047 
01048         nsXPIDLString profile;
01049         rv = node->GetName(getter_Copies(profile));
01050         if (NS_FAILED(rv)) return rv;
01051 
01052         // Unescape is done on the profileName to interpret special characters like %, _ etc.
01053         // For example something like %20 would probably be interpreted as a space
01054         // There is some problem I guess in sending a space as itself
01055         // NOTE: This needs to be done BEFORE the test for existence.
01056 
01057 #if defined(XP_MAC) || defined(XP_MACOSX)
01058         // 4.x profiles coming from japanese machine are already in unicode.
01059         // So, there is no need to decode into unicode further.
01060         NS_ConvertUTF16toUTF8 temp(profile);
01061         nsCAutoString profileName(nsUnescape(temp.BeginWriting()));
01062         NS_ConvertUTF8toUTF16 convertedProfName(profileName);
01063 #else
01064         nsCAutoString temp;
01065         NS_CopyUnicodeToNative(profile, temp);
01066         nsCAutoString profileName(nsUnescape(temp.BeginWriting()));
01067         nsAutoString convertedProfName;
01068         NS_CopyNativeToUnicode(profileName, convertedProfName);
01069 #endif
01070 
01071         PRBool exists = PR_FALSE;
01072         if (!fromImport) {
01073             exists = ProfileExists(convertedProfName.get());
01074             if (exists)
01075             {
01076                 rv = enumKeys->Next();
01077                 if (NS_FAILED(rv)) return rv;
01078                 continue;
01079             }
01080         }
01081 
01082         nsRegistryKey key;
01083         rv = node->GetKey(&key);
01084         if (NS_FAILED(rv)) return rv;
01085 
01086         ProfileStruct*  profileItem  = new ProfileStruct();
01087         if (!profileItem)
01088             return NS_ERROR_OUT_OF_MEMORY;
01089 
01090         profileItem->updateProfileEntry    = PR_TRUE;
01091         profileItem->profileName  = convertedProfName;
01092         rv = profileItem->InternalizeLocation(oldReg, key, PR_TRUE);
01093         NS_ASSERTION(NS_SUCCEEDED(rv), "Could not get 4x profile location");
01094         profileItem->isMigrated = PR_FALSE;
01095         profileItem->isImportType = fromImport;
01096 
01097         SetValue(profileItem);
01098 
01099         rv = enumKeys->Next();
01100         if (NS_FAILED(rv)) return rv;
01101     }
01102 
01103 #elif defined (XP_BEOS)
01104 #else
01105 /* XP_UNIX */
01106         nsCAutoString unixProfileName( PR_GetEnv(PROFILE_NAME_ENVIRONMENT_VARIABLE) );
01107         nsCAutoString unixProfileDirectory( PR_GetEnv(PROFILE_HOME_ENVIRONMENT_VARIABLE) );
01108 
01109         if (unixProfileName.IsEmpty()  ||
01110             unixProfileDirectory.IsEmpty())
01111         {
01112             unixProfileDirectory = PR_GetEnv(HOME_ENVIRONMENT_VARIABLE);
01113             unixProfileName = PR_GetEnv(LOGNAME_ENVIRONMENT_VARIABLE);
01114             if ( unixProfileName.IsEmpty() ) {
01115               unixProfileName = PR_GetEnv(USER_ENVIRONMENT_VARIABLE);
01116             }
01117             if ( unixProfileName.IsEmpty() ) {
01118               unixProfileName = DEFAULT_UNIX_PROFILE_NAME;
01119             }
01120         }
01121 
01122         PRBool exists = PR_FALSE;
01123         if (!fromImport) {
01124             nsAutoString profileNameUTF16;
01125             NS_CopyNativeToUnicode(unixProfileName, profileNameUTF16);
01126             exists = ProfileExists(profileNameUTF16.get());
01127             if (exists)
01128             {
01129                 return NS_OK;
01130             }
01131         }
01132         if ( ! unixProfileName.IsEmpty() && ! unixProfileDirectory.IsEmpty() ) {
01133             nsCAutoString profileLocation(unixProfileDirectory);
01134             profileLocation += "/.netscape";
01135 
01136             nsCOMPtr<nsILocalFile> fileInNSDir;
01137             rv = NS_NewNativeLocalFile(profileLocation + NS_LITERAL_CSTRING("/preferences.js"),
01138                                        PR_TRUE,
01139                                        getter_AddRefs(fileInNSDir));
01140             if (NS_FAILED(rv))
01141               return rv;
01142             rv = fileInNSDir->Exists(&exists);
01143 #ifdef DEBUG
01144             printf("%s/preferences.js exists:  %d\n",profileLocation.get(), NS_SUCCEEDED(rv) && exists);
01145 #endif
01146             if (NS_SUCCEEDED(rv) && exists) {
01147                 ProfileStruct*  profileItem     = new ProfileStruct();
01148                 if (!profileItem)
01149                     return NS_ERROR_OUT_OF_MEMORY;
01150 
01151                 profileItem->updateProfileEntry = PR_TRUE;
01152 
01153                 NS_CopyNativeToUnicode(unixProfileName, profileItem->profileName);
01154 
01155                 nsCOMPtr<nsILocalFile> localFile;
01156                 rv = NS_NewNativeLocalFile(profileLocation, PR_TRUE, getter_AddRefs(localFile));
01157                 if (NS_FAILED(rv)) return rv;
01158                 profileItem->SetResolvedProfileDir(localFile);
01159                 profileItem->isMigrated = PR_FALSE;
01160                 profileItem->isImportType = fromImport;
01161 
01162                 SetValue(profileItem);
01163             }
01164             else {
01165 #ifdef DEBUG
01166                 printf("no 4.x profile\n");
01167 #endif
01168             }
01169         }
01170 #endif /* XP_UNIX */
01171 
01172     return rv;
01173 }
01174 
01175 
01176 // Set the PREG flag to indicate if that info exists
01177 void
01178 nsProfileAccess::SetPREGInfo(const char* pregInfo)
01179 {
01180     NS_ASSERTION(pregInfo, "Invalid pregInfo");
01181 
01182     // This is always going to be just a yes/no string
01183     mHavePREGInfo.AssignWithConversion(pregInfo);
01184 }
01185 
01186 //Get the for PREG info.
01187 void
01188 nsProfileAccess::CheckRegString(const PRUnichar *profileName, char **info)
01189 {
01190     NS_ASSERTION(profileName, "Invalid profile name");
01191     NS_ASSERTION(info, "Invalid info pointer");
01192 
01193     *info = nsnull;
01194     PRInt32 index = 0;
01195 
01196     index = FindProfileIndex(profileName, PR_FALSE);
01197 
01198     if (index >= 0 )
01199     {
01200         ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
01201 
01202         if (!profileItem->NCHavePregInfo.IsEmpty()) {
01203             *info = ToNewCString(profileItem->NCHavePregInfo);
01204         }
01205         else
01206         {
01207             *info = ToNewCString(kRegistryNoString);
01208         }
01209     }
01210 }
01211 
01212 
01213 // Clear the profile member data structure
01214 // We need to fill in the data from the new registry
01215 nsresult
01216 nsProfileAccess::ResetProfileMembers()
01217 {
01218     FreeProfileMembers(mProfiles);
01219     mProfiles = new nsVoidArray();
01220     return NS_OK;
01221 }
01222 
01223 nsresult
01224 nsProfileAccess::DetermineForceMigration(PRBool *forceMigration)
01225 {
01226     if (!forceMigration) return NS_ERROR_NULL_POINTER;
01227 
01228     PRInt32 numProfiles;
01229     GetNumProfiles(&numProfiles);
01230 
01231     if (numProfiles > 0) {
01232         // we have some 6.0 profiles, don't force migration:
01233         *forceMigration = PR_FALSE;
01234             return NS_OK;
01235     }
01236 
01237     // even if we don't any 4.x profiles, running -installer is safe.  so do it
01238     *forceMigration = PR_TRUE;
01239     return NS_OK;
01240 }
01241 
01242 // **********************************************************************
01243 // class ProfileStruct
01244 // **********************************************************************
01245 
01246 ProfileStruct::ProfileStruct() :
01247     isMigrated(PR_FALSE), updateProfileEntry(PR_FALSE),
01248     isImportType(PR_FALSE),
01249     creationTime(LL_ZERO), lastModTime(LL_ZERO)
01250 {
01251 }
01252 
01253 ProfileStruct::ProfileStruct(const ProfileStruct& src)
01254 {
01255     *this = src;
01256 }
01257 
01258 ProfileStruct& ProfileStruct::operator=(const ProfileStruct& rhs)
01259 {
01260     profileName = rhs.profileName;
01261     isMigrated = rhs.isMigrated;
01262     NCProfileName = rhs.NCProfileName;
01263     NCDeniedService = rhs.NCDeniedService;
01264     NCEmailAddress = rhs.NCEmailAddress;
01265     NCHavePregInfo = rhs.NCHavePregInfo;
01266     updateProfileEntry = rhs.updateProfileEntry;
01267     isImportType = rhs.isImportType;
01268     creationTime = rhs.creationTime;
01269     lastModTime = rhs.lastModTime;
01270 
01271     nsresult rv;
01272         nsCOMPtr<nsIFile> file;
01273 
01274     resolvedLocation = nsnull;
01275     if (rhs.resolvedLocation) {
01276         regLocationData.Truncate(0);
01277         rv = rhs.resolvedLocation->Clone(getter_AddRefs(file));
01278         if (NS_SUCCEEDED(rv))
01279             resolvedLocation = do_QueryInterface(file);
01280         file = nsnull;
01281     }
01282     else
01283         regLocationData = rhs.regLocationData;
01284 
01285     migratedFrom = nsnull;
01286     if (rhs.migratedFrom) {
01287         rv = rhs.migratedFrom->Clone(getter_AddRefs(file));
01288         if (NS_SUCCEEDED(rv))
01289             migratedFrom = do_QueryInterface(file);
01290     }
01291 
01292     return *this;
01293 }
01294 
01295 nsresult ProfileStruct::GetResolvedProfileDir(nsILocalFile **aDirectory)
01296 {
01297     NS_ENSURE_ARG_POINTER(aDirectory);
01298     *aDirectory = nsnull;
01299     if (resolvedLocation)
01300     {
01301         *aDirectory = resolvedLocation;
01302         NS_ADDREF(*aDirectory);
01303         return NS_OK;
01304     }
01305     return NS_ERROR_FILE_NOT_FOUND; // The only reason it would not exist.
01306 }
01307 
01308 nsresult ProfileStruct::SetResolvedProfileDir(nsILocalFile *aDirectory)
01309 {
01310     NS_ENSURE_ARG(aDirectory);
01311     resolvedLocation = aDirectory;
01312     regLocationData.SetLength(0);
01313     return NS_OK;
01314 }
01315 
01316 nsresult ProfileStruct::CopyProfileLocation(ProfileStruct *destStruct)
01317 {
01318     if (resolvedLocation)
01319     {
01320         nsCOMPtr<nsIFile> file;
01321         nsresult rv = resolvedLocation->Clone(getter_AddRefs(file));
01322         if (NS_SUCCEEDED(rv))
01323             destStruct->resolvedLocation = do_QueryInterface(file, &rv);
01324         if (NS_FAILED(rv)) return rv;
01325     }
01326     destStruct->regLocationData = regLocationData;
01327 
01328     return NS_OK;
01329 }
01330 
01331 nsresult ProfileStruct::InternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey, PRBool is4x)
01332 {
01333     nsresult rv;
01334     nsCOMPtr<nsILocalFile> tempLocal;
01335 
01336     // Reset ourselves
01337     regLocationData.SetLength(0);
01338     resolvedLocation = nsnull;
01339 
01340     if (is4x)
01341     {
01342         nsXPIDLString profLoc;
01343 
01344         rv = aRegistry->GetString( profKey, NS_LITERAL_STRING("ProfileLocation").get(), getter_Copies(profLoc));
01345         if (NS_FAILED(rv)) return rv;
01346         regLocationData = profLoc;
01347 
01348 #if defined(XP_MAC) || defined(XP_MACOSX)
01349         // 4.x profiles coming from japanese machine are already in unicode.
01350         // So, there is no need to decode into unicode further.
01351 
01352         // Unescape profile location
01353         NS_ConvertUTF16toUTF8 tempLoc(profLoc);
01354         nsCAutoString profileLocation(nsUnescape(tempLoc.BeginWriting()));
01355         NS_ConvertUTF8toUTF16 convertedProfLoc(profileLocation);
01356 
01357         // Now we have a unicode path - make it into a file
01358         // This is an HFS style path, which can't be used with nsIFile, so convert it.
01359         rv = NS_ERROR_FAILURE;
01360         CFStringRef pathStrRef = ::CFStringCreateWithCharacters(NULL,
01361                                       convertedProfLoc.get(), convertedProfLoc.Length());
01362         if (pathStrRef)
01363         {
01364             CFURLRef pathURLRef = ::CFURLCreateWithFileSystemPath(NULL, pathStrRef, kCFURLHFSPathStyle, true);
01365             if (pathURLRef)
01366             {
01367                 rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(tempLocal));
01368                 if (NS_SUCCEEDED(rv))
01369                 {
01370                     nsCOMPtr<nsILocalFileMac> tempLocalMac(do_QueryInterface(tempLocal));
01371                     rv = tempLocalMac->InitWithCFURL(pathURLRef);
01372                 }
01373                 ::CFRelease(pathURLRef);
01374             }
01375             ::CFRelease(pathStrRef);
01376         }
01377 #else        
01378         // Unescape profile location and convert it to the right format
01379         nsCAutoString tempLoc;
01380         rv = NS_CopyUnicodeToNative(profLoc, tempLoc); 
01381         NS_ASSERTION(NS_SUCCEEDED(rv), 
01382                      "failed to convert profile location to native encoding");
01383         nsCAutoString profileLocation(nsUnescape(tempLoc.BeginWriting()));
01384         rv = NS_NewNativeLocalFile(profileLocation, PR_TRUE, getter_AddRefs(tempLocal));
01385 #endif
01386     }
01387     else
01388     {
01389         nsXPIDLString regData;
01390 
01391         rv = aRegistry->GetString(profKey,
01392                                   kRegistryDirectoryString.get(),
01393                                   getter_Copies(regData));
01394         if (NS_FAILED(rv)) return rv;
01395         regLocationData = regData;
01396 
01397 #if defined(XP_MAC) || defined(XP_MACOSX)
01398             rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(tempLocal));
01399         if (NS_SUCCEEDED(rv)) // regLocationData is ASCII so no loss
01400             rv = tempLocal->SetPersistentDescriptor(NS_LossyConvertUCS2toASCII(regLocationData));
01401 #else
01402         rv = NS_NewLocalFile(regLocationData, PR_TRUE, getter_AddRefs(tempLocal));
01403 #endif
01404     }
01405 
01406     if (NS_SUCCEEDED(rv) && tempLocal)
01407     {
01408         PRBool exists;
01409         if (NS_SUCCEEDED(tempLocal->Exists(&exists)) && exists)
01410             SetResolvedProfileDir(tempLocal);
01411     }
01412 
01413     return NS_OK;
01414 }
01415 
01416 nsresult ProfileStruct::ExternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey)
01417 {
01418     nsresult rv;
01419 
01420     if (resolvedLocation)
01421     {
01422         nsAutoString regData;
01423 
01424 #if defined(XP_MAC) || defined(XP_MACOSX)
01425         PRBool leafCreated;
01426         nsCAutoString descBuf;
01427 
01428         // It must exist before we try to use GetPersistentDescriptor
01429         rv = EnsureDirPathExists(resolvedLocation, &leafCreated);
01430         if (NS_FAILED(rv)) return rv;
01431         rv = resolvedLocation->GetPersistentDescriptor(descBuf);
01432         if (NS_FAILED(rv)) return rv;
01433         if (leafCreated)
01434             resolvedLocation->Remove(PR_FALSE);
01435         AppendUTF8toUTF16(descBuf, regData);
01436 #else
01437         rv = resolvedLocation->GetPath(regData);
01438         if (NS_FAILED(rv)) return rv;
01439 #endif
01440 
01441         rv = aRegistry->SetString(profKey,
01442                                  kRegistryDirectoryString.get(),
01443                                  regData.get());
01444 
01445     }
01446     else if (!regLocationData.IsEmpty())
01447     {
01448         // Write the original data back out - maybe it can be resolved later.
01449         rv = aRegistry->SetString(profKey,
01450                                  kRegistryDirectoryString.get(),
01451                                  regLocationData.get());
01452     }
01453     else
01454     {
01455         NS_ASSERTION(PR_FALSE, "ProfileStruct has no location data!");
01456         rv = NS_ERROR_FAILURE;
01457     }
01458 
01459     return rv;
01460 }
01461 
01462 nsresult ProfileStruct::InternalizeMigratedFromLocation(nsIRegistry *aRegistry, nsRegistryKey profKey)
01463 {
01464     nsresult rv;
01465     nsXPIDLCString regData;
01466     nsCOMPtr<nsILocalFile> tempLocal;
01467 
01468     rv = aRegistry->GetStringUTF8(profKey,
01469                                   kRegistryMigratedFromString.get(),
01470                                   getter_Copies(regData));
01471     if (NS_SUCCEEDED(rv))
01472     {
01473 #if defined(XP_MAC) || defined(XP_MACOSX)
01474         rv = NS_NewLocalFile(EmptyString(), PR_TRUE, getter_AddRefs(tempLocal));
01475         if (NS_SUCCEEDED(rv))
01476         {
01477             // The persistent desc on Mac is base64 encoded so plain ASCII
01478             rv = tempLocal->SetPersistentDescriptor(regData);
01479             if (NS_SUCCEEDED(rv))
01480                 migratedFrom = tempLocal;
01481         }
01482 #else
01483         rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(regData), PR_TRUE, getter_AddRefs(tempLocal));
01484         if (NS_SUCCEEDED(rv))
01485             migratedFrom = tempLocal;
01486 #endif
01487     }
01488     return rv;
01489 }
01490 
01491 nsresult ProfileStruct::ExternalizeMigratedFromLocation(nsIRegistry *aRegistry, nsRegistryKey profKey)
01492 {
01493     nsresult rv = NS_OK;
01494     nsCAutoString regData;
01495 
01496     if (migratedFrom)
01497     {
01498 #if defined(XP_MAC) || defined(XP_MACOSX)
01499         rv = migratedFrom->GetPersistentDescriptor(regData);
01500 #else
01501         nsAutoString path;
01502         rv = migratedFrom->GetPath(path);
01503         AppendUTF16toUTF8(path, regData);
01504 #endif
01505 
01506         if (NS_SUCCEEDED(rv))
01507             rv = aRegistry->SetStringUTF8(profKey,
01508                                           kRegistryMigratedFromString.get(),
01509                                           regData.get());
01510     }
01511     return rv;
01512 }
01513 
01514 nsresult ProfileStruct::EnsureDirPathExists(nsILocalFile *aDir, PRBool *wasCreated)
01515 {
01516     NS_ENSURE_ARG(aDir);
01517     NS_ENSURE_ARG_POINTER(wasCreated);
01518     *wasCreated = PR_FALSE;
01519 
01520     nsresult rv;
01521     PRBool exists;
01522     rv = aDir->Exists(&exists);
01523     if (NS_SUCCEEDED(rv) && !exists)
01524     {
01525         rv = aDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
01526         *wasCreated = NS_SUCCEEDED(rv);
01527     }
01528     return rv;
01529 }
01530