Back to index

lightning-sunbird  0.9+nobinonly
nsAppFileLocationProvider.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 Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Conrad Carlen <conrad@ingress.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 "nsAppFileLocationProvider.h"
00041 #include "nsAppDirectoryServiceDefs.h"
00042 #include "nsDirectoryServiceDefs.h"
00043 #include "nsIAtom.h"
00044 #include "nsILocalFile.h"
00045 #include "nsString.h"
00046 #include "nsXPIDLString.h"
00047 #include "nsISimpleEnumerator.h"
00048 #include "prenv.h"
00049 #include "nsCRT.h"
00050 
00051 #if defined(XP_MAC) || defined(XP_MACOSX)
00052 #include <Folders.h>
00053 #include <Script.h>
00054 #include <Processes.h>
00055 #include <Gestalt.h>
00056 #include "nsILocalFileMac.h"
00057 #elif defined(XP_OS2)
00058 #define INCL_DOSPROCESS
00059 #define INCL_DOSMODULEMGR
00060 #include <os2.h>
00061 #elif defined(XP_WIN)
00062 #include <windows.h>
00063 #include <shlobj.h>
00064 #elif defined(XP_UNIX)
00065 #include <unistd.h>
00066 #include <stdlib.h>
00067 #include <sys/param.h>
00068 #elif defined(XP_BEOS)
00069 #include <sys/param.h>
00070 #include <kernel/image.h>
00071 #include <storage/FindDirectory.h>
00072 #endif
00073 
00074 
00075 // WARNING: These hard coded names need to go away. They need to
00076 // come from localizable resources
00077 
00078 #if defined(XP_MAC) || defined(XP_MACOSX)
00079 #define APP_REGISTRY_NAME NS_LITERAL_CSTRING("Application Registry")
00080 #define ESSENTIAL_FILES   NS_LITERAL_CSTRING("Essential Files")
00081 #elif defined(XP_WIN) || defined(XP_OS2)
00082 #define APP_REGISTRY_NAME NS_LITERAL_CSTRING("registry.dat")
00083 #else
00084 #define APP_REGISTRY_NAME NS_LITERAL_CSTRING("appreg")
00085 #endif
00086 
00087 // define default product directory
00088 #if defined (XP_MAC) || defined (WINCE)
00089 #define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING("Mozilla")
00090 #else
00091 #define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING(MOZ_USER_DIR)
00092 #endif
00093 
00094 // Locally defined keys used by nsAppDirectoryEnumerator
00095 #define NS_ENV_PLUGINS_DIR          "EnvPlugins"    // env var MOZ_PLUGIN_PATH
00096 #define NS_USER_PLUGINS_DIR         "UserPlugins"
00097 
00098 #if defined(XP_MAC) || defined(XP_MACOSX)
00099 #define NS_MACOSX_USER_PLUGIN_DIR   "OSXUserPlugins"
00100 #define NS_MACOSX_LOCAL_PLUGIN_DIR  "OSXLocalPlugins"
00101 #define NS_MAC_CLASSIC_PLUGIN_DIR   "MacSysPlugins"
00102 #endif
00103 
00104 #if defined(XP_MAC)
00105 #define DEFAULTS_DIR_NAME           NS_LITERAL_CSTRING("Defaults")
00106 #define DEFAULTS_PREF_DIR_NAME      NS_LITERAL_CSTRING("Pref")
00107 #define DEFAULTS_PROFILE_DIR_NAME   NS_LITERAL_CSTRING("Profile")
00108 #define RES_DIR_NAME                NS_LITERAL_CSTRING("Res")
00109 #define CHROME_DIR_NAME             NS_LITERAL_CSTRING("Chrome")
00110 #define PLUGINS_DIR_NAME            NS_LITERAL_CSTRING("Plug-ins")
00111 #define SEARCH_DIR_NAME             NS_LITERAL_CSTRING("Search Plugins")
00112 #else
00113 #define DEFAULTS_DIR_NAME           NS_LITERAL_CSTRING("defaults")
00114 #define DEFAULTS_PREF_DIR_NAME      NS_LITERAL_CSTRING("pref")
00115 #define DEFAULTS_PROFILE_DIR_NAME   NS_LITERAL_CSTRING("profile")
00116 #define RES_DIR_NAME                NS_LITERAL_CSTRING("res")
00117 #define CHROME_DIR_NAME             NS_LITERAL_CSTRING("chrome")
00118 #define PLUGINS_DIR_NAME            NS_LITERAL_CSTRING("plugins")
00119 #define SEARCH_DIR_NAME             NS_LITERAL_CSTRING("searchplugins")
00120 #endif
00121 
00122 //*****************************************************************************
00123 // nsAppFileLocationProvider::Constructor/Destructor
00124 //*****************************************************************************
00125 
00126 nsAppFileLocationProvider::nsAppFileLocationProvider()
00127 {
00128 }
00129 
00130 //*****************************************************************************
00131 // nsAppFileLocationProvider::nsISupports
00132 //*****************************************************************************
00133 
00134 NS_IMPL_THREADSAFE_ISUPPORTS2(nsAppFileLocationProvider, nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2)
00135 
00136 //*****************************************************************************
00137 // nsAppFileLocationProvider::nsIDirectoryServiceProvider
00138 //*****************************************************************************
00139 
00140 NS_IMETHODIMP
00141 nsAppFileLocationProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval)
00142 {
00143     nsCOMPtr<nsILocalFile>  localFile;
00144     nsresult rv = NS_ERROR_FAILURE;
00145 
00146     NS_ENSURE_ARG(prop);
00147     *_retval = nsnull;
00148     *persistant = PR_TRUE;
00149 
00150 #if defined (XP_MAC) || defined(XP_MACOSX)
00151     short foundVRefNum;
00152     long foundDirID;
00153     FSSpec fileSpec;
00154     nsCOMPtr<nsILocalFileMac> macFile;
00155 #endif
00156     
00157     if (nsCRT::strcmp(prop, NS_APP_APPLICATION_REGISTRY_DIR) == 0)
00158     {
00159         rv = GetProductDirectory(getter_AddRefs(localFile));
00160     }
00161     else if (nsCRT::strcmp(prop, NS_APP_APPLICATION_REGISTRY_FILE) == 0)
00162     {
00163         rv = GetProductDirectory(getter_AddRefs(localFile));
00164         if (NS_SUCCEEDED(rv))
00165             rv = localFile->AppendNative(APP_REGISTRY_NAME);
00166     }
00167     else if (nsCRT::strcmp(prop, NS_APP_DEFAULTS_50_DIR) == 0)
00168     {
00169         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00170         if (NS_SUCCEEDED(rv))
00171             rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME);
00172     }
00173     else if (nsCRT::strcmp(prop, NS_APP_PREF_DEFAULTS_50_DIR) == 0)
00174     {
00175         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00176         if (NS_SUCCEEDED(rv)) {
00177             rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME);
00178             if (NS_SUCCEEDED(rv))
00179                 rv = localFile->AppendRelativeNativePath(DEFAULTS_PREF_DIR_NAME);
00180         }
00181     }
00182     else if (nsCRT::strcmp(prop, NS_APP_PROFILE_DEFAULTS_50_DIR) == 0 ||
00183              nsCRT::strcmp(prop, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR) == 0)
00184     {
00185         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00186         if (NS_SUCCEEDED(rv)) {
00187             rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME);
00188             if (NS_SUCCEEDED(rv))
00189                 rv = localFile->AppendRelativeNativePath(DEFAULTS_PROFILE_DIR_NAME);
00190         }
00191     }
00192     else if (nsCRT::strcmp(prop, NS_APP_USER_PROFILES_ROOT_DIR) == 0)
00193     {
00194         rv = GetDefaultUserProfileRoot(getter_AddRefs(localFile));
00195     }
00196     else if (nsCRT::strcmp(prop, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR) == 0)
00197     {
00198         rv = GetDefaultUserProfileRoot(getter_AddRefs(localFile), PR_TRUE);
00199     }
00200     else if (nsCRT::strcmp(prop, NS_APP_RES_DIR) == 0)
00201     {
00202         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00203         if (NS_SUCCEEDED(rv))
00204             rv = localFile->AppendRelativeNativePath(RES_DIR_NAME);
00205     }
00206     else if (nsCRT::strcmp(prop, NS_APP_CHROME_DIR) == 0)
00207     {
00208         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00209         if (NS_SUCCEEDED(rv))
00210             rv = localFile->AppendRelativeNativePath(CHROME_DIR_NAME);
00211     }
00212     else if (nsCRT::strcmp(prop, NS_APP_PLUGINS_DIR) == 0)
00213     {
00214         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00215         if (NS_SUCCEEDED(rv))
00216             rv = localFile->AppendRelativeNativePath(PLUGINS_DIR_NAME);
00217     }
00218 #if defined(XP_MAC) || defined(XP_MACOSX)
00219     else if (nsCRT::strcmp(prop, NS_MACOSX_USER_PLUGIN_DIR) == 0)
00220     {
00221         if (!(::FindFolder(kUserDomain,
00222                            kInternetPlugInFolderType,
00223                            kDontCreateFolder, &foundVRefNum, &foundDirID)) &&
00224             !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) {
00225             rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile));
00226             if (NS_SUCCEEDED(rv))
00227                 localFile = macFile;
00228         }
00229     }
00230     else if (nsCRT::strcmp(prop, NS_MACOSX_LOCAL_PLUGIN_DIR) == 0)
00231     {
00232         if (!(::FindFolder(kLocalDomain,
00233                            kInternetPlugInFolderType,
00234                            kDontCreateFolder, &foundVRefNum, &foundDirID)) &&
00235             !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) {
00236             rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile));
00237             if (NS_SUCCEEDED(rv))
00238                 localFile = macFile;
00239         }
00240     }
00241     else if (nsCRT::strcmp(prop, NS_MAC_CLASSIC_PLUGIN_DIR) == 0)
00242     {
00243         if (!(::FindFolder(kOnAppropriateDisk,
00244                            kInternetPlugInFolderType,
00245                            kDontCreateFolder, &foundVRefNum, &foundDirID)) &&
00246             !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) {
00247             rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile));
00248             if (NS_SUCCEEDED(rv))
00249                 localFile = macFile;
00250         }
00251     }
00252 #else
00253     else if (nsCRT::strcmp(prop, NS_ENV_PLUGINS_DIR) == 0)
00254     {
00255         NS_ERROR("Don't use nsAppFileLocationProvider::GetFile(NS_ENV_PLUGINS_DIR, ...). "
00256                  "Use nsAppFileLocationProvider::GetFiles(...).");
00257         const char *pathVar = PR_GetEnv("MOZ_PLUGIN_PATH");
00258         if (pathVar)
00259             rv = NS_NewNativeLocalFile(nsDependentCString(pathVar), PR_TRUE, getter_AddRefs(localFile));
00260     }
00261     else if (nsCRT::strcmp(prop, NS_USER_PLUGINS_DIR) == 0)
00262     {
00263         rv = GetProductDirectory(getter_AddRefs(localFile));
00264         if (NS_SUCCEEDED(rv))
00265             rv = localFile->AppendRelativeNativePath(PLUGINS_DIR_NAME);
00266     }
00267 #endif
00268     else if (nsCRT::strcmp(prop, NS_APP_SEARCH_DIR) == 0)
00269     {
00270         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00271         if (NS_SUCCEEDED(rv))
00272             rv = localFile->AppendRelativeNativePath(SEARCH_DIR_NAME);
00273     }
00274     else if (nsCRT::strcmp(prop, NS_APP_USER_SEARCH_DIR) == 0)
00275     {
00276         rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, _retval);
00277         if (NS_SUCCEEDED(rv))
00278             rv = (*_retval)->AppendNative(SEARCH_DIR_NAME);
00279     }
00280     else if (nsCRT::strcmp(prop, NS_APP_INSTALL_CLEANUP_DIR) == 0)
00281     {   
00282         // This is cloned so that embeddors will have a hook to override
00283         // with their own cleanup dir.  See bugzilla bug #105087 
00284         rv = CloneMozBinDirectory(getter_AddRefs(localFile));
00285 #ifdef XP_MAC
00286         if (NS_SUCCEEDED(rv))
00287             rv = localFile->AppendNative(ESSENTIAL_FILES);
00288 #endif
00289 
00290     } 
00291 
00292     if (localFile && NS_SUCCEEDED(rv))
00293         return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval);
00294         
00295     return rv;
00296 }
00297 
00298 
00299 NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsILocalFile **aLocalFile)
00300 {
00301     NS_ENSURE_ARG_POINTER(aLocalFile);
00302     nsresult rv;
00303 
00304     if (!mMozBinDirectory)
00305     {
00306         // Get the mozilla bin directory
00307         // 1. Check the directory service first for NS_XPCOM_CURRENT_PROCESS_DIR
00308         //    This will be set if a directory was passed to NS_InitXPCOM
00309         // 2. If that doesn't work, set it to be the current process directory
00310         nsCOMPtr<nsIProperties>
00311           directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
00312         if (NS_FAILED(rv))
00313             return rv;
00314 
00315         rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mMozBinDirectory));
00316         if (NS_FAILED(rv)) {
00317             rv = directoryService->Get(NS_OS_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mMozBinDirectory));
00318             if (NS_FAILED(rv))
00319                 return rv;
00320         }
00321     }
00322 
00323     nsCOMPtr<nsIFile> aFile;
00324     rv = mMozBinDirectory->Clone(getter_AddRefs(aFile));
00325     if (NS_FAILED(rv))
00326         return rv;
00327 
00328     nsCOMPtr<nsILocalFile> lfile = do_QueryInterface (aFile);
00329     if (!lfile)
00330         return NS_ERROR_FAILURE;
00331 
00332     NS_IF_ADDREF(*aLocalFile = lfile);
00333     return NS_OK;
00334 }
00335 
00336 
00337 //----------------------------------------------------------------------------------------
00338 // GetProductDirectory - Gets the directory which contains the application data folder
00339 //
00340 // UNIX   : ~/.mozilla/
00341 // WIN    : <Application Data folder on user's machine>\Mozilla
00342 // Mac    : :Documents:Mozilla:
00343 //----------------------------------------------------------------------------------------
00344 NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsILocalFile **aLocalFile, PRBool aLocal)
00345 {
00346     NS_ENSURE_ARG_POINTER(aLocalFile);
00347 
00348     nsresult rv;
00349     PRBool exists;
00350     nsCOMPtr<nsILocalFile> localDir;
00351 
00352 #if defined(XP_MAC)
00353     nsCOMPtr<nsIProperties> directoryService = 
00354              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00355     if (NS_FAILED(rv)) return rv;
00356     OSErr   err;
00357     long    response;
00358     err = ::Gestalt(gestaltSystemVersion, &response);
00359     const char *prop = (!err && response >= 0x00001000) ? NS_MAC_USER_LIB_DIR : NS_MAC_DOCUMENTS_DIR;
00360     rv = directoryService->Get(prop, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir));
00361     if (NS_FAILED(rv)) return rv;
00362 #elif defined(XP_MACOSX)
00363     FSRef fsRef;
00364     OSType folderType = aLocal ? kCachedDataFolderType : kDomainLibraryFolderType;
00365     OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
00366     if (err) return NS_ERROR_FAILURE;
00367     NS_NewLocalFile(EmptyString(), PR_TRUE, getter_AddRefs(localDir));
00368     if (!localDir) return NS_ERROR_FAILURE;
00369     nsCOMPtr<nsILocalFileMac> localDirMac(do_QueryInterface(localDir));
00370     rv = localDirMac->InitWithFSRef(&fsRef);
00371     if (NS_FAILED(rv)) return rv;
00372 #elif defined(XP_OS2)
00373     nsCOMPtr<nsIProperties> directoryService = 
00374              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00375     if (NS_FAILED(rv)) return rv;
00376     rv = directoryService->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir));
00377     if (NS_FAILED(rv)) return rv;
00378 #elif defined(WINCE)
00379     nsCOMPtr<nsIProperties> directoryService = 
00380              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00381     if (NS_FAILED(rv)) return rv;
00382 
00383     directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir));
00384     if (localDir)
00385         rv = localDir->AppendNative(NS_LITERAL_CSTRING("profile"));
00386     if (NS_FAILED(rv)) return rv;
00387 #elif defined(XP_WIN)
00388     nsCOMPtr<nsIProperties> directoryService = 
00389              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00390     if (NS_FAILED(rv)) return rv;
00391     const char* prop = aLocal ? NS_WIN_LOCAL_APPDATA_DIR : NS_WIN_APPDATA_DIR;
00392     rv = directoryService->Get(prop, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir));
00393     if (NS_SUCCEEDED(rv))
00394         rv = localDir->Exists(&exists);
00395     if (NS_FAILED(rv) || !exists)
00396     {
00397         // On some Win95 machines, NS_WIN_APPDATA_DIR does not exist - revert to NS_WIN_WINDOWS_DIR
00398         localDir = nsnull;
00399         rv = directoryService->Get(NS_WIN_WINDOWS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir));
00400     }
00401     if (NS_FAILED(rv)) return rv;
00402 #elif defined(XP_UNIX)
00403     rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), PR_TRUE, getter_AddRefs(localDir));
00404     if (NS_FAILED(rv)) return rv;
00405 #elif defined(XP_BEOS)
00406     char path[MAXPATHLEN];
00407     find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN);
00408     // Need enough space to add the trailing backslash
00409     int len = strlen(path);
00410     if (len > MAXPATHLEN-2)
00411         return NS_ERROR_FAILURE;
00412     path[len]   = '/';
00413     path[len+1] = '\0';
00414     rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_TRUE, getter_AddRefs(localDir));
00415     if (NS_FAILED(rv)) return rv;
00416 #else
00417 #error dont_know_how_to_get_product_dir_on_your_platform
00418 #endif
00419 
00420     rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR);
00421     if (NS_FAILED(rv)) return rv;
00422     rv = localDir->Exists(&exists);
00423 
00424     if (NS_SUCCEEDED(rv) && !exists)
00425         rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
00426 
00427     if (NS_FAILED(rv)) return rv;
00428 
00429     *aLocalFile = localDir;
00430     NS_ADDREF(*aLocalFile);
00431 
00432    return rv;
00433 }
00434 
00435 
00436 //----------------------------------------------------------------------------------------
00437 // GetDefaultUserProfileRoot - Gets the directory which contains each user profile dir
00438 //
00439 // UNIX   : ~/.mozilla/
00440 // WIN    : <Application Data folder on user's machine>\Mozilla\Profiles
00441 // Mac    : :Documents:Mozilla:Profiles:
00442 //----------------------------------------------------------------------------------------
00443 NS_METHOD nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsILocalFile **aLocalFile, PRBool aLocal)
00444 {
00445     NS_ENSURE_ARG_POINTER(aLocalFile);
00446 
00447     nsresult rv;
00448     nsCOMPtr<nsILocalFile> localDir;
00449 
00450     rv = GetProductDirectory(getter_AddRefs(localDir), aLocal);
00451     if (NS_FAILED(rv)) return rv;
00452 
00453 #if defined(XP_MAC) || defined(XP_MACOSX) || defined(XP_OS2) || defined(XP_WIN)
00454     // These 3 platforms share this part of the path - do them as one
00455     rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Profiles"));
00456     if (NS_FAILED(rv)) return rv;
00457 
00458     PRBool exists;
00459     rv = localDir->Exists(&exists);
00460     if (NS_SUCCEEDED(rv) && !exists)
00461         rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
00462     if (NS_FAILED(rv)) return rv;
00463 #endif
00464 
00465     *aLocalFile = localDir;
00466     NS_ADDREF(*aLocalFile);
00467 
00468    return rv;
00469 }
00470 
00471 //*****************************************************************************
00472 // nsAppFileLocationProvider::nsIDirectoryServiceProvider2
00473 //*****************************************************************************
00474 
00475 class nsAppDirectoryEnumerator : public nsISimpleEnumerator
00476 {
00477   public:
00478     NS_DECL_ISUPPORTS
00479 
00484     nsAppDirectoryEnumerator(nsIDirectoryServiceProvider *aProvider,
00485                              const char* aKeyList[]) :
00486         mProvider(aProvider),
00487         mCurrentKey(aKeyList)
00488     {
00489     }
00490 
00491     NS_IMETHOD HasMoreElements(PRBool *result) 
00492     {
00493         while (!mNext && *mCurrentKey)
00494         {
00495             PRBool dontCare;
00496             nsCOMPtr<nsIFile> testFile;
00497             (void)mProvider->GetFile(*mCurrentKey++, &dontCare, getter_AddRefs(testFile));
00498             // Don't return a file which does not exist.
00499             PRBool exists;
00500             if (testFile && NS_SUCCEEDED(testFile->Exists(&exists)) && exists)
00501                 mNext = testFile;
00502         }
00503         *result = mNext != nsnull;
00504         return NS_OK;
00505     }
00506 
00507     NS_IMETHOD GetNext(nsISupports **result) 
00508     {
00509         NS_ENSURE_ARG_POINTER(result);
00510         *result = nsnull;
00511 
00512         PRBool hasMore;
00513         HasMoreElements(&hasMore);
00514         if (!hasMore)
00515             return NS_ERROR_FAILURE;
00516             
00517         *result = mNext;
00518         NS_IF_ADDREF(*result);
00519         mNext = nsnull;
00520         
00521         return *result ? NS_OK : NS_ERROR_FAILURE;
00522     }
00523 
00524     // Virtual destructor since subclass nsPathsDirectoryEnumerator
00525     // does not re-implement Release()
00526 
00527     virtual ~nsAppDirectoryEnumerator()
00528     {
00529     }
00530 
00531   protected:
00532     nsIDirectoryServiceProvider *mProvider;
00533     const char** mCurrentKey;
00534     nsCOMPtr<nsIFile> mNext;
00535 };
00536 
00537 NS_IMPL_ISUPPORTS1(nsAppDirectoryEnumerator, nsISimpleEnumerator)
00538 
00539 /* nsPathsDirectoryEnumerator and PATH_SEPARATOR
00540  * are not used on MacOS/X. */
00541 
00542 #if defined(XP_WIN) || defined(XP_OS2)/* Win32, Win16, and OS/2 */
00543 #define PATH_SEPARATOR ';'
00544 #else /*if defined(XP_UNIX) || defined(XP_BEOS)*/
00545 #define PATH_SEPARATOR ':'
00546 #endif
00547 
00548 class nsPathsDirectoryEnumerator : public nsAppDirectoryEnumerator
00549 {
00550   public:
00557     nsPathsDirectoryEnumerator(nsIDirectoryServiceProvider *aProvider,
00558                                const char* aKeyList[]) :
00559     nsAppDirectoryEnumerator(aProvider, aKeyList+1),
00560     mEndPath(aKeyList[0])
00561     {
00562     }
00563 
00564     NS_IMETHOD HasMoreElements(PRBool *result) 
00565     {
00566         if (mEndPath)
00567             while (!mNext && *mEndPath)
00568             {
00569                 const char *pathVar = mEndPath;
00570                 do { ++mEndPath; } while (*mEndPath && *mEndPath != PATH_SEPARATOR);
00571 
00572                 nsCOMPtr<nsILocalFile> localFile;
00573                 NS_NewNativeLocalFile(Substring(pathVar, mEndPath),
00574                                       PR_TRUE,
00575                                       getter_AddRefs(localFile));
00576                 if (*mEndPath == PATH_SEPARATOR)
00577                     ++mEndPath;
00578                 // Don't return a "file" (directory) which does not exist.
00579                 PRBool exists;
00580                 if (localFile &&
00581                     NS_SUCCEEDED(localFile->Exists(&exists)) &&
00582                     exists)
00583                     mNext = localFile;
00584             }
00585         if (mNext)
00586             *result = PR_TRUE;
00587         else
00588             nsAppDirectoryEnumerator::HasMoreElements(result);
00589 
00590         return NS_OK;
00591     }
00592 
00593   protected:
00594     const char *mEndPath;
00595 };
00596 
00597 NS_IMETHODIMP
00598 nsAppFileLocationProvider::GetFiles(const char *prop, nsISimpleEnumerator **_retval)
00599 {
00600     NS_ENSURE_ARG_POINTER(_retval);
00601     *_retval = nsnull;
00602     nsresult rv = NS_ERROR_FAILURE;
00603     
00604     if (!nsCRT::strcmp(prop, NS_APP_PLUGINS_DIR_LIST))
00605     {
00606 #if defined(XP_MAC) || defined(XP_MACOSX)
00607         static const char* osXKeys[] = { NS_APP_PLUGINS_DIR, NS_MACOSX_USER_PLUGIN_DIR, NS_MACOSX_LOCAL_PLUGIN_DIR, nsnull };
00608         static const char* os9Keys[] = { NS_APP_PLUGINS_DIR, NS_MAC_CLASSIC_PLUGIN_DIR, nsnull };
00609         static const char** keys;
00610         
00611         if (!keys) {
00612             OSErr err;
00613             long response;
00614             err = ::Gestalt(gestaltSystemVersion, &response); 
00615             keys = (!err && response >= 0x00001000) ? osXKeys : os9Keys;
00616         }
00617 
00618         *_retval = new nsAppDirectoryEnumerator(this, keys);
00619 #else
00620         static const char* keys[] = { nsnull, NS_USER_PLUGINS_DIR, NS_APP_PLUGINS_DIR, nsnull };
00621         if (!keys[0] && !(keys[0] = PR_GetEnv("MOZ_PLUGIN_PATH"))) {
00622             static const char nullstr = 0;
00623             keys[0] = &nullstr;
00624         }
00625         *_retval = new nsPathsDirectoryEnumerator(this, keys);
00626 #endif
00627         NS_IF_ADDREF(*_retval);
00628         rv = *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;        
00629     }
00630     if (!nsCRT::strcmp(prop, NS_APP_SEARCH_DIR_LIST))
00631     {
00632         static const char* keys[] = { nsnull, NS_APP_SEARCH_DIR, NS_APP_USER_SEARCH_DIR, nsnull };
00633         if (!keys[0] && !(keys[0] = PR_GetEnv("MOZ_SEARCH_ENGINE_PATH"))) {
00634             static const char nullstr = 0;
00635             keys[0] = &nullstr;
00636         }
00637         *_retval = new nsPathsDirectoryEnumerator(this, keys);
00638         NS_IF_ADDREF(*_retval);
00639         rv = *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;        
00640     }
00641     return rv;
00642 }