Back to index

lightning-sunbird  0.9+nobinonly
nsToolkitProfileService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; 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 the new Mozilla toolkit.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Benjamin Smedberg <bsmedberg@covad.net>
00019  * Portions created by the Initial Developer are Copyright (C) 2004
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 the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include "nsProfileLock.h"
00041 
00042 #ifdef XP_WIN
00043 #include <windows.h>
00044 #include <shlobj.h>
00045 #endif
00046 #ifdef XP_BEOS
00047 #include <Path.h>
00048 #endif
00049 #ifdef XP_UNIX
00050 #include <unistd.h>
00051 #endif
00052 
00053 #include "nsIToolkitProfileService.h"
00054 #include "nsIToolkitProfile.h"
00055 #include "nsIFactory.h"
00056 #include "nsILocalFile.h"
00057 #include "nsISimpleEnumerator.h"
00058 
00059 #ifdef XP_MACOSX
00060 #include <CFURL.h>
00061 #include "nsILocalFileMac.h"
00062 #endif
00063 
00064 #include "nsAppDirectoryServiceDefs.h"
00065 #include "nsXULAppAPI.h"
00066 
00067 #include "nsINIParser.h"
00068 #include "nsXREDirProvider.h"
00069 #include "nsAppRunner.h"
00070 #include "nsString.h"
00071 #include "nsReadableUtils.h"
00072 
00073 
00074 class nsToolkitProfile : public nsIToolkitProfile
00075 {
00076 public:
00077     NS_DECL_ISUPPORTS
00078     NS_DECL_NSITOOLKITPROFILE
00079 
00080     friend class nsToolkitProfileService;
00081     nsCOMPtr<nsToolkitProfile> mNext;
00082     nsToolkitProfile          *mPrev;
00083 
00084     ~nsToolkitProfile() { }
00085 
00086 private:
00087     nsToolkitProfile(const nsACString& aName,
00088                      nsILocalFile* aRootDir,
00089                      nsILocalFile* aLocalDir,
00090                      nsToolkitProfile* aPrev);
00091 
00092     friend class nsToolkitProfileLock;
00093 
00094     nsCString                  mName;
00095     nsCOMPtr<nsILocalFile>     mRootDir;
00096     nsCOMPtr<nsILocalFile>     mLocalDir;
00097     nsIProfileLock*            mLock;
00098 };
00099 
00100 class nsToolkitProfileLock : public nsIProfileLock
00101 {
00102 public:
00103     NS_DECL_ISUPPORTS
00104     NS_DECL_NSIPROFILELOCK
00105 
00106     nsresult Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker);
00107     nsresult Init(nsILocalFile* aDirectory, nsILocalFile* aLocalDirectory,
00108                   nsIProfileUnlocker* *aUnlocker);
00109 
00110     nsToolkitProfileLock() { }
00111     ~nsToolkitProfileLock();
00112 
00113 private:
00114     nsCOMPtr<nsToolkitProfile> mProfile;
00115     nsCOMPtr<nsILocalFile> mDirectory;
00116     nsCOMPtr<nsILocalFile> mLocalDirectory;
00117 
00118     nsProfileLock mLock;
00119 };
00120 
00121 class nsToolkitProfileService : public nsIToolkitProfileService,
00122                                 public nsIFactory
00123 {
00124 public:
00125     NS_DECL_ISUPPORTS
00126     NS_DECL_NSITOOLKITPROFILESERVICE
00127 
00128     // we implement nsIFactory because we can't be registered by location,
00129     // like most ordinary components are. Instead, during startup we register
00130     // our factory. Then we return our singleton-self when asked.
00131     NS_DECL_NSIFACTORY
00132 
00133 private:
00134     friend class nsToolkitProfile;
00135     friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**);
00136 
00137     nsToolkitProfileService() :
00138         mDirty(PR_FALSE),
00139         mStartWithLast(PR_TRUE),
00140         mStartOffline(PR_FALSE)
00141     {
00142         gService = this;
00143     }
00144     ~nsToolkitProfileService()
00145     {
00146         gService = nsnull;
00147     }
00148 
00149     NS_HIDDEN_(nsresult) Init();
00150 
00151     nsCOMPtr<nsToolkitProfile> mFirst;
00152     nsCOMPtr<nsToolkitProfile> mChosen;
00153     nsCOMPtr<nsILocalFile>     mAppData;
00154     nsCOMPtr<nsILocalFile>     mTempData;
00155     nsCOMPtr<nsILocalFile>     mListFile;
00156     PRBool mDirty;
00157     PRBool mStartWithLast;
00158     PRBool mStartOffline;
00159 
00160     static nsToolkitProfileService *gService;
00161 
00162     class ProfileEnumerator : public nsISimpleEnumerator
00163     {
00164     public:
00165         NS_DECL_ISUPPORTS
00166         NS_DECL_NSISIMPLEENUMERATOR
00167 
00168         ProfileEnumerator(nsToolkitProfile *first)
00169           { mCurrent = first; }
00170     private:
00171         ~ProfileEnumerator() { }
00172         nsCOMPtr<nsToolkitProfile> mCurrent;
00173     };
00174 };
00175 
00176 nsToolkitProfile::nsToolkitProfile(const nsACString& aName,
00177                                    nsILocalFile* aRootDir,
00178                                    nsILocalFile* aLocalDir,
00179                                    nsToolkitProfile* aPrev) :
00180     mPrev(aPrev),
00181     mName(aName),
00182     mRootDir(aRootDir),
00183     mLocalDir(aLocalDir),
00184     mLock(nsnull)
00185 {
00186     NS_ASSERTION(aRootDir, "No file!");
00187 
00188     if (aPrev)
00189         aPrev->mNext = this;
00190     else
00191         nsToolkitProfileService::gService->mFirst = this;
00192 }
00193 
00194 NS_IMPL_ISUPPORTS1(nsToolkitProfile, nsIToolkitProfile)
00195 
00196 NS_IMETHODIMP
00197 nsToolkitProfile::GetRootDir(nsILocalFile* *aResult)
00198 {
00199     NS_ADDREF(*aResult = mRootDir);
00200     return NS_OK;
00201 }
00202 
00203 NS_IMETHODIMP
00204 nsToolkitProfile::GetLocalDir(nsILocalFile* *aResult)
00205 {
00206     NS_ADDREF(*aResult = mLocalDir);
00207     return NS_OK;
00208 }
00209 
00210 NS_IMETHODIMP
00211 nsToolkitProfile::GetName(nsACString& aResult)
00212 {
00213     aResult = mName;
00214     return NS_OK;
00215 }
00216 
00217 NS_IMETHODIMP
00218 nsToolkitProfile::SetName(const nsACString& aName)
00219 {
00220     NS_ASSERTION(nsToolkitProfileService::gService,
00221                  "Where did my service go?");
00222 
00223     mName = aName;
00224     nsToolkitProfileService::gService->mDirty = PR_TRUE;
00225 
00226     return NS_OK;
00227 }
00228 
00229 NS_IMETHODIMP
00230 nsToolkitProfile::Remove(PRBool removeFiles)
00231 {
00232     NS_ASSERTION(nsToolkitProfileService::gService,
00233                  "Whoa, my service is gone.");
00234 
00235     if (mLock)
00236         return NS_ERROR_FILE_IS_LOCKED;
00237 
00238     if (removeFiles) {
00239         PRBool equals;
00240         nsresult rv = mRootDir->Equals(mLocalDir, &equals);
00241         if (NS_FAILED(rv))
00242             return rv;
00243 
00244         // The root dir might contain the temp dir, so remove
00245         // the temp dir first.
00246         if (!equals)
00247             mLocalDir->Remove(PR_TRUE);
00248 
00249         mRootDir->Remove(PR_TRUE);
00250     }
00251 
00252     if (mPrev)
00253         mPrev->mNext = mNext;
00254     else
00255         nsToolkitProfileService::gService->mFirst = mNext;
00256 
00257     if (mNext)
00258         mNext->mPrev = mPrev;
00259 
00260     mPrev = nsnull;
00261     mNext = nsnull;
00262 
00263     if (nsToolkitProfileService::gService->mChosen == this)
00264         nsToolkitProfileService::gService->mChosen = nsnull;
00265 
00266     nsToolkitProfileService::gService->mDirty = PR_TRUE;
00267 
00268     return NS_OK;
00269 }
00270 
00271 NS_IMETHODIMP
00272 nsToolkitProfile::Lock(nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
00273 {
00274     if (mLock) {
00275         NS_ADDREF(*aResult = mLock);
00276         return NS_OK;
00277     }
00278 
00279     nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
00280     if (!lock) return NS_ERROR_OUT_OF_MEMORY;
00281 
00282     nsresult rv = lock->Init(this, aUnlocker);
00283     if (NS_FAILED(rv)) return rv;
00284 
00285     NS_ADDREF(*aResult = lock);
00286     return NS_OK;
00287 }
00288 
00289 NS_IMPL_ISUPPORTS1(nsToolkitProfileLock, nsIProfileLock)
00290 
00291 nsresult
00292 nsToolkitProfileLock::Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker)
00293 {
00294     nsresult rv;
00295     rv = Init(aProfile->mRootDir, aProfile->mLocalDir, aUnlocker);
00296     if (NS_SUCCEEDED(rv))
00297         mProfile = aProfile;
00298 
00299     return rv;
00300 }
00301 
00302 nsresult
00303 nsToolkitProfileLock::Init(nsILocalFile* aDirectory, nsILocalFile* aLocalDirectory,
00304                            nsIProfileUnlocker* *aUnlocker)
00305 {
00306     nsresult rv;
00307 
00308     rv = mLock.Lock(aDirectory, aUnlocker);
00309 
00310     if (NS_SUCCEEDED(rv)) {
00311         mDirectory = aDirectory;
00312         mLocalDirectory = aLocalDirectory;
00313     }
00314 
00315     return rv;
00316 }
00317 
00318 NS_IMETHODIMP
00319 nsToolkitProfileLock::GetDirectory(nsILocalFile* *aResult)
00320 {
00321     if (!mDirectory) {
00322         NS_ERROR("Not initialized, or unlocked!");
00323         return NS_ERROR_NOT_INITIALIZED;
00324     }
00325 
00326     NS_ADDREF(*aResult = mDirectory);
00327     return NS_OK;
00328 }
00329 
00330 NS_IMETHODIMP
00331 nsToolkitProfileLock::GetLocalDirectory(nsILocalFile* *aResult)
00332 {
00333     if (!mLocalDirectory) {
00334         NS_ERROR("Not initialized, or unlocked!");
00335         return NS_ERROR_NOT_INITIALIZED;
00336     }
00337 
00338     NS_ADDREF(*aResult = mLocalDirectory);
00339     return NS_OK;
00340 }
00341 
00342 NS_IMETHODIMP
00343 nsToolkitProfileLock::Unlock()
00344 {
00345     if (!mDirectory) {
00346         NS_ERROR("Unlocking a never-locked nsToolkitProfileLock!");
00347         return NS_ERROR_UNEXPECTED;
00348     }
00349 
00350     mLock.Unlock();
00351 
00352     if (mProfile) {
00353         mProfile->mLock = nsnull;
00354         mProfile = nsnull;
00355     }
00356     mDirectory = nsnull;
00357     mLocalDirectory = nsnull;
00358 
00359     return NS_OK;
00360 }
00361 
00362 nsToolkitProfileLock::~nsToolkitProfileLock()
00363 {
00364     if (mDirectory) {
00365         Unlock();
00366     }
00367 }
00368 
00369 nsToolkitProfileService*
00370 nsToolkitProfileService::gService = nsnull;
00371 
00372 NS_IMPL_ISUPPORTS2(nsToolkitProfileService,
00373                    nsIToolkitProfileService,
00374                    nsIFactory)
00375 
00376 nsresult
00377 nsToolkitProfileService::Init()
00378 {
00379     NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!");
00380     nsresult rv;
00381 
00382     rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData));
00383     NS_ENSURE_SUCCESS(rv, rv);
00384 
00385     rv = gDirServiceProvider->GetUserLocalDataDirectory(getter_AddRefs(mTempData));
00386     NS_ENSURE_SUCCESS(rv, rv);
00387 
00388     nsCOMPtr<nsIFile> listFile;
00389     rv = mAppData->Clone(getter_AddRefs(listFile));
00390     NS_ENSURE_SUCCESS(rv, rv);
00391 
00392     mListFile = do_QueryInterface(listFile);
00393     NS_ENSURE_TRUE(listFile, NS_ERROR_NO_INTERFACE);
00394 
00395     rv = mListFile->AppendNative(NS_LITERAL_CSTRING("profiles.ini"));
00396     NS_ENSURE_SUCCESS(rv, rv);
00397 
00398     PRBool exists;
00399     rv = mListFile->IsFile(&exists);
00400     if (NS_FAILED(rv) || !exists) {
00401         return NS_OK;
00402     }
00403 
00404     nsINIParser parser;
00405     rv = parser.Init(mListFile);
00406     // Init does not fail on parsing errors, only on OOM/really unexpected
00407     // conditions.
00408     if (NS_FAILED(rv))
00409         return rv;
00410 
00411     nsCAutoString buffer;
00412     rv = parser.GetString("General", "StartWithLastProfile", buffer);
00413     if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("0"))
00414         mStartWithLast = PR_FALSE;
00415 
00416     nsToolkitProfile* currentProfile = nsnull;
00417 
00418     unsigned int c = 0;
00419     for (c = 0; PR_TRUE; ++c) {
00420         nsCAutoString profileID("Profile");
00421         profileID.AppendInt(c);
00422 
00423         rv = parser.GetString(profileID.get(), "IsRelative", buffer);
00424         if (NS_FAILED(rv)) break;
00425 
00426         PRBool isRelative = buffer.EqualsLiteral("1");
00427 
00428         nsCAutoString filePath;
00429 
00430         rv = parser.GetString(profileID.get(), "Path", filePath);
00431         if (NS_FAILED(rv)) {
00432             NS_ERROR("Malformed profiles.ini: Path= not found");
00433             continue;
00434         }
00435 
00436         rv = parser.GetString(profileID.get(), "Name", buffer);
00437         if (NS_FAILED(rv)) {
00438             NS_ERROR("Malformed profiles.ini: Name= not found");
00439             continue;
00440         }
00441 
00442         nsCOMPtr<nsILocalFile> rootDir;
00443         rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE,
00444                                    getter_AddRefs(rootDir));
00445         NS_ENSURE_SUCCESS(rv, rv);
00446 
00447         if (isRelative) {
00448             rv = rootDir->SetRelativeDescriptor(mAppData, filePath);
00449         } else {
00450             rv = rootDir->SetPersistentDescriptor(filePath);
00451         }
00452         if (NS_FAILED(rv)) continue;
00453 
00454         nsCOMPtr<nsILocalFile> localDir;
00455         if (isRelative) {
00456             rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE,
00457                                        getter_AddRefs(localDir));
00458             NS_ENSURE_SUCCESS(rv, rv);
00459 
00460             rv = localDir->SetRelativeDescriptor(mTempData, filePath);
00461         } else {
00462             localDir = rootDir;
00463         }
00464 
00465         currentProfile = new nsToolkitProfile(buffer,
00466                                               rootDir, localDir,
00467                                               currentProfile);
00468         NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
00469 
00470         rv = parser.GetString(profileID.get(), "Default", buffer);
00471         if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1"))
00472             mChosen = currentProfile;
00473     }
00474 
00475     return NS_OK;
00476 }
00477 
00478 NS_IMETHODIMP
00479 nsToolkitProfileService::SetStartWithLastProfile(PRBool aValue)
00480 {
00481     if (mStartWithLast != aValue) {
00482         mStartWithLast = aValue;
00483         mDirty = PR_TRUE;
00484     }
00485     return NS_OK;
00486 }
00487 
00488 NS_IMETHODIMP
00489 nsToolkitProfileService::GetStartWithLastProfile(PRBool *aResult)
00490 {
00491     *aResult = mStartWithLast;
00492     return NS_OK;
00493 }
00494 
00495 NS_IMETHODIMP
00496 nsToolkitProfileService::GetStartOffline(PRBool *aResult)
00497 {
00498     *aResult = mStartOffline;
00499     return NS_OK;
00500 }
00501 
00502 NS_IMETHODIMP
00503 nsToolkitProfileService::SetStartOffline(PRBool aValue)
00504 {
00505     mStartOffline = aValue;
00506     return NS_OK;
00507 }
00508 
00509 NS_IMETHODIMP
00510 nsToolkitProfileService::GetProfiles(nsISimpleEnumerator* *aResult)
00511 {
00512     *aResult = new ProfileEnumerator(this->mFirst);
00513     if (!*aResult)
00514         return NS_ERROR_OUT_OF_MEMORY;
00515 
00516     NS_ADDREF(*aResult);
00517     return NS_OK;
00518 }
00519 
00520 NS_IMPL_ISUPPORTS1(nsToolkitProfileService::ProfileEnumerator,
00521                    nsISimpleEnumerator)
00522 
00523 NS_IMETHODIMP
00524 nsToolkitProfileService::ProfileEnumerator::HasMoreElements(PRBool* aResult)
00525 {
00526     *aResult = mCurrent ? PR_TRUE : PR_FALSE;
00527     return NS_OK;
00528 }
00529 
00530 NS_IMETHODIMP
00531 nsToolkitProfileService::ProfileEnumerator::GetNext(nsISupports* *aResult)
00532 {
00533     if (!mCurrent) return NS_ERROR_FAILURE;
00534 
00535     NS_ADDREF(*aResult = mCurrent);
00536 
00537     mCurrent = mCurrent->mNext;
00538     return NS_OK;
00539 }
00540 
00541 NS_IMETHODIMP
00542 nsToolkitProfileService::GetSelectedProfile(nsIToolkitProfile* *aResult)
00543 {
00544     if (!mChosen && mFirst && !mFirst->mNext) // only one profile
00545         mChosen = mFirst;
00546 
00547     if (!mChosen) return NS_ERROR_FAILURE;
00548 
00549     NS_ADDREF(*aResult = mChosen);
00550     return NS_OK;
00551 }
00552 
00553 NS_IMETHODIMP
00554 nsToolkitProfileService::SetSelectedProfile(nsIToolkitProfile* aProfile)
00555 {
00556     if (mChosen != aProfile) {
00557         // XXXbz Why is this cast OK?
00558         mChosen = NS_STATIC_CAST(nsToolkitProfile*, aProfile);
00559         mDirty = PR_TRUE;
00560     }
00561     return NS_OK;
00562 }
00563 
00564 NS_IMETHODIMP
00565 nsToolkitProfileService::GetProfileByName(const nsACString& aName,
00566                                           nsIToolkitProfile* *aResult)
00567 {
00568     nsToolkitProfile* curP = mFirst;
00569     while (curP) {
00570         if (curP->mName.Equals(aName)) {
00571             NS_ADDREF(*aResult = curP);
00572             return NS_OK;
00573         }
00574         curP = curP->mNext;
00575     }
00576 
00577     return NS_ERROR_FAILURE;
00578 }
00579 
00580 NS_IMETHODIMP
00581 nsToolkitProfileService::LockProfilePath(nsILocalFile* aDirectory,
00582                                          nsILocalFile* aLocalDirectory,
00583                                          nsIProfileLock* *aResult)
00584 {
00585     return NS_LockProfilePath(aDirectory, aLocalDirectory, nsnull, aResult);
00586 }
00587 
00588 nsresult
00589 NS_LockProfilePath(nsILocalFile* aPath, nsILocalFile* aTempPath,
00590                    nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
00591 {
00592     nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
00593     if (!lock) return NS_ERROR_OUT_OF_MEMORY;
00594 
00595     nsresult rv = lock->Init(aPath, aTempPath, aUnlocker);
00596     if (NS_FAILED(rv)) return rv;
00597 
00598     NS_ADDREF(*aResult = lock);
00599     return NS_OK;
00600 }
00601 
00602 static const char kTable[] =
00603     { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00604       'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
00605       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
00606 
00607 static void SaltProfileName(nsACString& aName)
00608 {
00609     double fpTime;
00610     LL_L2D(fpTime, PR_Now());
00611 
00612     // use 1e-6, granularity of PR_Now() on the mac is seconds
00613     srand((uint)(fpTime * 1e-6 + 0.5));
00614 
00615     char salt[9];
00616 
00617     int i;
00618     for (i = 0; i < 8; ++i)
00619         salt[i] = kTable[rand() % NS_ARRAY_LENGTH(kTable)];
00620 
00621     salt[8] = '.';
00622 
00623     aName.Insert(salt, 0, 9);
00624 }
00625 
00626 NS_IMETHODIMP
00627 nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
00628                                        nsILocalFile* aLocalDir,
00629                                        const nsACString& aName,
00630                                        nsIToolkitProfile* *aResult)
00631 {
00632     nsresult rv;
00633 
00634     rv = GetProfileByName(aName, aResult);
00635     if (NS_SUCCEEDED(rv)) return rv;
00636 
00637     nsCOMPtr<nsILocalFile> rootDir (aRootDir);
00638 
00639     nsCAutoString dirName;
00640     if (!rootDir) {
00641         nsCOMPtr<nsIFile> file;
00642         PRBool dummy;
00643         rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_ROOT_DIR, &dummy,
00644                                           getter_AddRefs(file));
00645         NS_ENSURE_SUCCESS(rv, rv);
00646 
00647         rootDir = do_QueryInterface(file);
00648         NS_ENSURE_TRUE(rootDir, NS_ERROR_UNEXPECTED);
00649 
00650         dirName = aName;
00651         SaltProfileName(dirName);
00652 
00653         rootDir->AppendNative(dirName);
00654     }
00655 
00656     nsCOMPtr<nsILocalFile> localDir (aLocalDir);
00657 
00658     if (!localDir) {
00659         if (aRootDir) {
00660             localDir = aRootDir;
00661         }
00662         else {
00663             nsCOMPtr<nsIFile> file;
00664             PRBool dummy;
00665             rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_LOCAL_ROOT_DIR,
00666                                               &dummy, getter_AddRefs(file));
00667             NS_ENSURE_SUCCESS(rv, rv);
00668 
00669             localDir = do_QueryInterface(file);
00670             NS_ENSURE_TRUE(localDir, NS_ERROR_UNEXPECTED);
00671 
00672             // use same salting
00673             localDir->AppendNative(dirName);
00674         }
00675     }
00676 
00677     PRBool exists;
00678     rv = rootDir->Exists(&exists);
00679     NS_ENSURE_SUCCESS(rv, rv);
00680 
00681     if (exists) {
00682         rv = rootDir->IsDirectory(&exists);
00683         NS_ENSURE_SUCCESS(rv, rv);
00684 
00685         if (!exists)
00686             return NS_ERROR_FILE_NOT_DIRECTORY;
00687     }
00688     else {
00689         nsCOMPtr<nsIFile> profileDefaultsDir;
00690         nsCOMPtr<nsIFile> profileDirParent;
00691         nsCAutoString profileDirName;
00692 
00693         rv = rootDir->GetParent(getter_AddRefs(profileDirParent));
00694         NS_ENSURE_SUCCESS(rv, rv);
00695 
00696         rv = rootDir->GetNativeLeafName(profileDirName);
00697         NS_ENSURE_SUCCESS(rv, rv);
00698 
00699         PRBool dummy;
00700         rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy,
00701                                           getter_AddRefs(profileDefaultsDir));
00702 
00703         if (NS_SUCCEEDED(rv))
00704             rv = profileDefaultsDir->CopyToNative(profileDirParent,
00705                                                   profileDirName);
00706         if (NS_FAILED(rv)) {
00707             // if copying failed, lets just ensure that the profile directory exists.
00708             rv = rootDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
00709             NS_ENSURE_SUCCESS(rv, rv);
00710         }
00711       
00712         rv = rootDir->SetPermissions(0700);
00713         NS_ENSURE_SUCCESS(rv, rv);
00714     }
00715 
00716     rv = localDir->Exists(&exists);
00717     NS_ENSURE_SUCCESS(rv, rv);
00718 
00719     if (!exists) {
00720         rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
00721         NS_ENSURE_SUCCESS(rv, rv);
00722     }
00723 
00724     nsToolkitProfile* last = mFirst;
00725     if (last) {
00726         while (last->mNext)
00727             last = last->mNext;
00728     }
00729 
00730     nsCOMPtr<nsIToolkitProfile> profile =
00731         new nsToolkitProfile(aName, rootDir, localDir, last);
00732     if (!profile) return NS_ERROR_OUT_OF_MEMORY;
00733 
00734     NS_ADDREF(*aResult = profile);
00735     return NS_OK;
00736 }
00737 
00738 NS_IMETHODIMP
00739 nsToolkitProfileService::GetProfileCount(PRUint32 *aResult)
00740 {
00741     if (!mFirst)
00742         *aResult = 0;
00743     else if (! mFirst->mNext)
00744         *aResult = 1;
00745     else
00746         *aResult = 2;
00747 
00748     return NS_OK;
00749 }
00750 
00751 NS_IMETHODIMP
00752 nsToolkitProfileService::Flush()
00753 {
00754     // Errors during writing might cause unhappy semi-written files.
00755     // To avoid this, write the entire thing to a buffer, then write
00756     // that buffer to disk.
00757 
00758     nsresult rv;
00759     PRUint32 pCount = 0;
00760     nsToolkitProfile *cur;
00761 
00762     for (cur = mFirst; cur != nsnull; cur = cur->mNext)
00763         ++pCount;
00764 
00765     PRUint32 length;
00766 
00767     char* buffer = (char*) malloc(100 + MAXPATHLEN * pCount);
00768     NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
00769 
00770     char *end = buffer;
00771 
00772     end += sprintf(end,
00773                    "[General]\n"
00774                    "StartWithLastProfile=%s\n\n",
00775                    mStartWithLast ? "1" : "0");
00776 
00777     nsCAutoString path;
00778     cur = mFirst;
00779     pCount = 0;
00780 
00781     while (cur) {
00782         // if the profile dir is relative to appdir...
00783         PRBool isRelative;
00784         rv = mAppData->Contains(cur->mRootDir, PR_TRUE, &isRelative);
00785         if (NS_SUCCEEDED(rv) && isRelative) {
00786             // we use a relative descriptor
00787             rv = cur->mRootDir->GetRelativeDescriptor(mAppData, path);
00788         } else {
00789             // otherwise, a persistent descriptor
00790             rv = cur->mRootDir->GetPersistentDescriptor(path);
00791             NS_ENSURE_SUCCESS(rv, rv);
00792         }
00793 
00794         end += sprintf(end,
00795                        "[Profile%u]\n"
00796                        "Name=%s\n"
00797                        "IsRelative=%s\n"
00798                        "Path=%s\n",
00799                        pCount, cur->mName.get(),
00800                        isRelative ? "1" : "0", path.get());
00801 
00802         if (mChosen == cur) {
00803             end += sprintf(end, "Default=1\n");
00804         }
00805 
00806         end += sprintf(end, "\n");
00807 
00808         cur = cur->mNext;
00809         ++pCount;
00810     }
00811 
00812     FILE* writeFile;
00813     rv = mListFile->OpenANSIFileDesc("w", &writeFile);
00814     NS_ENSURE_SUCCESS(rv, rv);
00815 
00816     if (buffer) {
00817         length = end - buffer;
00818 
00819         if (fwrite(buffer, sizeof(char), length, writeFile) != length) {
00820             fclose(writeFile);
00821             return NS_ERROR_UNEXPECTED;
00822         }
00823     }
00824 
00825     fclose(writeFile);
00826     return NS_OK;
00827 }
00828 
00829 NS_IMETHODIMP
00830 nsToolkitProfileService::CreateInstance(nsISupports* aOuter, const nsID& aIID,
00831                                         void** aResult)
00832 {
00833     if (aOuter)
00834         return NS_ERROR_NO_AGGREGATION;
00835 
00836     // return this object
00837     return QueryInterface(aIID, aResult);
00838 }
00839 
00840 NS_IMETHODIMP
00841 nsToolkitProfileService::LockFactory(PRBool aVal)
00842 {
00843     return NS_OK;
00844 }
00845 
00846 nsresult
00847 NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult)
00848 {
00849     nsToolkitProfileService* aThis = new nsToolkitProfileService();
00850     nsresult rv = aThis->Init();
00851     if (NS_FAILED(rv)) {
00852         NS_ERROR("nsToolkitProfileService::Init failed!");
00853         delete aThis;
00854         return rv;
00855     }
00856 
00857     NS_ADDREF(*aResult = aThis);
00858     return NS_OK;
00859 }
00860 
00861 nsresult
00862 XRE_GetFileFromPath(const char *aPath, nsILocalFile* *aResult)
00863 {
00864 #if defined(XP_MACOSX)
00865     PRInt32 pathLen = strlen(aPath);
00866     if (pathLen > MAXPATHLEN)
00867         return NS_ERROR_INVALID_ARG;
00868 
00869     CFURLRef fullPath =
00870         CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *) aPath,
00871                                                 pathLen, true);
00872     if (!fullPath)
00873         return NS_ERROR_FAILURE;
00874 
00875     nsCOMPtr<nsILocalFile> lf;
00876     nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE,
00877                                         getter_AddRefs(lf));
00878     if (NS_SUCCEEDED(rv)) {
00879         nsCOMPtr<nsILocalFileMac> lfMac = do_QueryInterface(lf, &rv);
00880         if (NS_SUCCEEDED(rv)) {
00881             rv = lfMac->InitWithCFURL(fullPath);
00882             if (NS_SUCCEEDED(rv))
00883                 NS_ADDREF(*aResult = lf);
00884         }
00885     }
00886     CFRelease(fullPath);
00887     return rv;
00888 
00889 #elif defined(XP_UNIX)
00890     char fullPath[MAXPATHLEN];
00891 
00892     if (!realpath(aPath, fullPath))
00893         return NS_ERROR_FAILURE;
00894 
00895     return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
00896                                  aResult);
00897 #elif defined(XP_OS2)
00898     char fullPath[MAXPATHLEN];
00899 
00900     if (!realpath(aPath, fullPath))
00901         return NS_ERROR_FAILURE;
00902 
00903     // realpath on OS/2 returns a unix-ized path, so re-native-ize
00904     for (char* ptr = strchr(fullPath, '/'); ptr; ptr = strchr(ptr, '/'))
00905         *ptr = '\\';
00906 
00907     return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
00908                                  aResult);
00909 
00910 #elif defined(XP_WIN)
00911     char fullPath[MAXPATHLEN];
00912 
00913     if (!_fullpath(fullPath, aPath, MAXPATHLEN))
00914         return NS_ERROR_FAILURE;
00915 
00916     return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
00917                                  aResult);
00918 
00919 #elif defined(XP_BEOS)
00920     BPath fullPath;
00921     if (fullPath.SetTo(aPath, NULL, true))
00922         return NS_ERROR_FAILURE;
00923 
00924     return NS_NewNativeLocalFile(nsDependentCString(fullPath.Leaf()), PR_TRUE,
00925                                  aResult);
00926 
00927 #else
00928 #error Platform-specific logic needed here.
00929 #endif
00930 }