Back to index

lightning-sunbird  0.9+nobinonly
nsXREDirProvider.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Brian Ryner <bryner@brianryner.com>
00024  *  Benjamin Smedberg <bsmedberg@covad.net>
00025  *  Ben Goodger <ben@mozilla.org>
00026  *  Jens Bannmann <jens.b@web.de>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsAppRunner.h"
00043 #include "nsXREDirProvider.h"
00044 
00045 #include "jsapi.h"
00046 
00047 #include "nsIJSContextStack.h"
00048 #include "nsILocalFile.h"
00049 #include "nsIObserverService.h"
00050 #include "nsIProfileChangeStatus.h"
00051 #include "nsIToolkitChromeRegistry.h"
00052 
00053 #include "nsAppDirectoryServiceDefs.h"
00054 #include "nsDirectoryServiceDefs.h"
00055 #include "nsXULAppAPI.h"
00056 
00057 #include "nsINIParser.h"
00058 #include "nsDependentString.h"
00059 #include "nsCOMArray.h"
00060 #include "nsArrayEnumerator.h"
00061 
00062 #include <stdlib.h>
00063 
00064 #ifdef XP_WIN
00065 #include <windows.h>
00066 #include <shlobj.h>
00067 // This is not defined by VC6. 
00068 #ifndef CSIDL_LOCAL_APPDATA
00069 #define CSIDL_LOCAL_APPDATA             0x001C
00070 #endif
00071 #ifndef CSIDL_PROGRAM_FILES
00072 #define CSIDL_PROGRAM_FILES             0x0026
00073 #endif
00074 #endif
00075 #ifdef XP_MACOSX
00076 #include "nsILocalFileMac.h"
00077 #endif
00078 #ifdef XP_BEOS
00079 #include <be/kernel/image.h>
00080 #include <FindDirectory.h>
00081 #endif
00082 #ifdef XP_UNIX
00083 #include <ctype.h>
00084 #endif
00085 #ifdef XP_OS2
00086 #define INCL_DOS
00087 #include <os2.h>
00088 #endif
00089 
00090 #if defined(XP_MACOSX)
00091 #define APP_REGISTRY_NAME "Application Registry"
00092 #elif defined(XP_WIN) || defined(XP_OS2)
00093 #define APP_REGISTRY_NAME "registry.dat"
00094 #else
00095 #define APP_REGISTRY_NAME "appreg"
00096 #endif
00097 
00098 #define PREF_OVERRIDE_DIRNAME "preferences"
00099 
00100 nsXREDirProvider* gDirServiceProvider = nsnull;
00101 
00102 nsXREDirProvider::nsXREDirProvider() :
00103   mProfileNotified(PR_FALSE)
00104 {
00105   gDirServiceProvider = this;
00106 }
00107 
00108 nsXREDirProvider::~nsXREDirProvider()
00109 {
00110   gDirServiceProvider = nsnull;
00111 }
00112 
00113 nsresult
00114 nsXREDirProvider::Initialize(nsIFile *aXULAppDir)
00115 { 
00116   mXULAppDir = aXULAppDir;
00117 
00118   nsCOMPtr<nsILocalFile> lf;
00119   nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
00120   if (NS_FAILED(rv))
00121     return rv;
00122 
00123   nsCOMPtr<nsIFile> appDir;
00124   rv = lf->GetParent(getter_AddRefs(appDir));
00125   if (NS_FAILED(rv))
00126     return rv;
00127 
00128   mAppDir = do_QueryInterface(appDir);
00129   if (!mAppDir)
00130     return NS_ERROR_FAILURE;
00131 
00132   return NS_OK;
00133 }
00134 
00135 nsresult
00136 nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
00137 {
00138   NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
00139 
00140   nsresult rv;
00141   
00142   rv = EnsureDirectoryExists(aDir);
00143   if (NS_FAILED(rv))
00144     return rv;
00145 
00146   rv = EnsureDirectoryExists(aLocalDir);
00147   if (NS_FAILED(rv))
00148     return rv;
00149 
00150   mProfileDir = aDir;
00151   mProfileLocalDir = aLocalDir;
00152   return NS_OK;
00153 }
00154 
00155 NS_IMPL_QUERY_INTERFACE3(nsXREDirProvider,
00156                          nsIDirectoryServiceProvider,
00157                          nsIDirectoryServiceProvider2,
00158                          nsIProfileStartup)
00159 
00160 NS_IMETHODIMP_(nsrefcnt)
00161 nsXREDirProvider::AddRef()
00162 {
00163   return 1;
00164 }
00165 
00166 NS_IMETHODIMP_(nsrefcnt)
00167 nsXREDirProvider::Release()
00168 {
00169   return 0;
00170 }
00171 
00172 NS_IMETHODIMP
00173 nsXREDirProvider::GetFile(const char* aProperty, PRBool* aPersistent,
00174                        nsIFile** aFile)
00175 {
00176   nsresult rv = NS_ERROR_FAILURE;
00177   *aPersistent = PR_TRUE;
00178   nsCOMPtr<nsIFile> file;
00179   PRBool ensureFilePermissions = PR_FALSE;
00180 
00181   if (!strcmp(aProperty, NS_OS_CURRENT_PROCESS_DIR) ||
00182       !strcmp(aProperty, NS_APP_INSTALL_CLEANUP_DIR)) {
00183     // NOTE: this is *different* than NS_XPCOM_CURRENT_PROCESS_DIR. This points
00184     // to the application dir. NS_XPCOM_CURRENT_PROCESS_DIR points to the toolkit.
00185     return mAppDir->Clone(aFile);
00186   }
00187   else if (!strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_50_DIR) ||
00188            !strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR)) {
00189     return GetProfileDefaultsDir(aFile);
00190   }
00191   else if (!strcmp(aProperty, NS_APP_PREF_DEFAULTS_50_DIR))
00192   {
00193     rv = mAppDir->Clone(getter_AddRefs(file));
00194     if (NS_SUCCEEDED(rv)) {
00195       rv = file->AppendNative(NS_LITERAL_CSTRING("defaults"));
00196       if (NS_SUCCEEDED(rv))
00197         rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
00198     }
00199   }
00200   else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
00201            !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
00202     rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
00203   }
00204 #ifdef XP_WIN
00205   else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
00206     rv = GetUpdateRootDir(getter_AddRefs(file));
00207   }
00208 #endif
00209   else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
00210     rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
00211     rv |= file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
00212   }
00213   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
00214     rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
00215 
00216 #if !defined(XP_UNIX) || defined(XP_MACOSX)
00217     rv |= file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
00218 #endif
00219 
00220     // We must create the profile directory here if it does not exist.
00221     rv |= EnsureDirectoryExists(file);
00222   }
00223   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
00224     rv = GetUserLocalDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
00225 
00226 #if !defined(XP_UNIX) || defined(XP_MACOSX)
00227     rv |= file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
00228 #endif
00229 
00230     // We must create the profile directory here if it does not exist.
00231     rv |= EnsureDirectoryExists(file);
00232   }
00233   else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE)) {
00234     nsCOMPtr<nsILocalFile> lf;
00235     rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
00236     if (NS_SUCCEEDED(rv))
00237       file = lf;
00238   }
00239   else if (mXULAppDir && !strcmp(aProperty, "resource:app")) {
00240     rv = mXULAppDir->Clone(getter_AddRefs(file));
00241   }
00242   else if (mProfileDir) {
00243     // We need to allow component, xpt, and chrome registration to
00244     // occur prior to the profile-after-change notification.
00245     if (!strcmp(aProperty, NS_XPCOM_COMPONENT_REGISTRY_FILE)) {
00246       rv = mProfileDir->Clone(getter_AddRefs(file));
00247       rv |= file->AppendNative(NS_LITERAL_CSTRING("compreg.dat"));
00248     }
00249     else if (!strcmp(aProperty, NS_XPCOM_XPTI_REGISTRY_FILE)) {
00250       rv = mProfileDir->Clone(getter_AddRefs(file));
00251       rv |= file->AppendNative(NS_LITERAL_CSTRING("xpti.dat"));
00252     }
00253     else if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
00254       rv = mProfileDir->Clone(getter_AddRefs(file));
00255       rv |= file->AppendNative(NS_LITERAL_CSTRING("chrome"));
00256     }
00257     else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
00258       return mProfileDir->Clone(aFile);
00259     }
00260     else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP) &&
00261              mProfileLocalDir) {
00262       return mProfileLocalDir->Clone(aFile);
00263     }
00264     else if (mProfileNotified) {
00265       if (!strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) ||
00266           !strcmp(aProperty, NS_APP_PREFS_50_DIR)) {
00267         return mProfileDir->Clone(aFile);
00268       }
00269       else if (!strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
00270         return mProfileLocalDir->Clone(aFile);
00271       }
00272       else if (!strcmp(aProperty, NS_APP_PREFS_50_FILE)) {
00273         rv = mProfileDir->Clone(getter_AddRefs(file));
00274         rv |= file->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
00275       }
00276       else if (!strcmp(aProperty, NS_LOCALSTORE_UNSAFE_FILE)) {
00277         rv = mProfileDir->Clone(getter_AddRefs(file));
00278         rv |= file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
00279       }
00280       else if (!strcmp(aProperty, NS_APP_LOCALSTORE_50_FILE)) {
00281         rv = mProfileDir->Clone(getter_AddRefs(file));
00282         if (gSafeMode) {
00283           rv |= file->AppendNative(NS_LITERAL_CSTRING("localstore-safe.rdf"));
00284           file->Remove(PR_FALSE);
00285         }
00286         else {
00287           rv |= file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
00288           EnsureProfileFileExists(file);
00289           ensureFilePermissions = PR_TRUE;
00290         }
00291       }
00292       else if (!strcmp(aProperty, NS_APP_HISTORY_50_FILE)) {
00293         rv = mProfileDir->Clone(getter_AddRefs(file));
00294         rv |= file->AppendNative(NS_LITERAL_CSTRING("history.dat"));
00295       }
00296       else if (!strcmp(aProperty, NS_APP_USER_MIMETYPES_50_FILE)) {
00297         rv = mProfileDir->Clone(getter_AddRefs(file));
00298         rv |= file->AppendNative(NS_LITERAL_CSTRING("mimeTypes.rdf"));
00299         EnsureProfileFileExists(file);
00300         ensureFilePermissions = PR_TRUE;
00301       }
00302       else if (!strcmp(aProperty, NS_APP_STORAGE_50_FILE)) {
00303         rv = mProfileDir->Clone(getter_AddRefs(file));
00304         rv |= file->AppendNative(NS_LITERAL_CSTRING("storage.sdb"));
00305       }
00306       else if (!strcmp(aProperty, NS_APP_DOWNLOADS_50_FILE)) {
00307         rv = mProfileDir->Clone(getter_AddRefs(file));
00308         rv |= file->AppendNative(NS_LITERAL_CSTRING("downloads.rdf"));
00309       }
00310       else if (!strcmp(aProperty, NS_APP_PREFS_OVERRIDE_DIR)) {
00311         rv = mProfileDir->Clone(getter_AddRefs(file));
00312         rv |= file->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
00313         rv |= EnsureDirectoryExists(file);
00314       }
00315       // XXXbsmedberg move these defines into application-specific providers.
00316       else if (!strcmp(aProperty, NS_APP_MAIL_50_DIR)) {
00317         rv = mProfileDir->Clone(getter_AddRefs(file));
00318         rv |= file->AppendNative(NS_LITERAL_CSTRING("Mail"));
00319       }
00320       else if (!strcmp(aProperty, NS_APP_IMAP_MAIL_50_DIR)) {
00321         rv = mProfileDir->Clone(getter_AddRefs(file));
00322         rv |= file->AppendNative(NS_LITERAL_CSTRING("ImapMail"));
00323       }
00324       else if (!strcmp(aProperty, NS_APP_NEWS_50_DIR)) {
00325         rv = mProfileDir->Clone(getter_AddRefs(file));
00326         rv |= file->AppendNative(NS_LITERAL_CSTRING("News"));
00327       }
00328       else if (!strcmp(aProperty, NS_APP_MESSENGER_FOLDER_CACHE_50_DIR)) {
00329         rv = mProfileDir->Clone(getter_AddRefs(file));
00330         rv |= file->AppendNative(NS_LITERAL_CSTRING("panacea.dat"));
00331       }
00332     }
00333   }
00334   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00335   if (!file) return NS_ERROR_FAILURE;
00336 
00337   if (ensureFilePermissions) {
00338     PRBool fileToEnsureExists;
00339     PRBool isWritable;
00340     if (NS_SUCCEEDED(file->Exists(&fileToEnsureExists)) && fileToEnsureExists
00341         && NS_SUCCEEDED(file->IsWritable(&isWritable)) && !isWritable) {
00342       PRUint32 permissions;
00343       if (NS_SUCCEEDED(file->GetPermissions(&permissions))) {
00344         rv = file->SetPermissions(permissions | 0600);
00345         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to ensure file permissions");
00346       }
00347     }
00348   }
00349 
00350   NS_ADDREF(*aFile = file);
00351   return NS_OK;
00352 }
00353 
00354 static void
00355 LoadDirsIntoArray(nsIFile* aComponentsList, const char* aSection,
00356                   const char *const* aAppendList,
00357                   nsCOMArray<nsIFile>& aDirectories)
00358 {
00359   nsINIParser parser;
00360   nsCOMPtr<nsILocalFile> lf(do_QueryInterface(aComponentsList));
00361   nsresult rv =  parser.Init(lf);
00362   if (NS_FAILED(rv))
00363     return;
00364 
00365   NS_NAMED_LITERAL_CSTRING(platform, "platform");
00366   NS_NAMED_LITERAL_CSTRING(osTarget, OS_TARGET);
00367 #ifdef TARGET_OS_ABI
00368   NS_NAMED_LITERAL_CSTRING(targetOSABI, TARGET_OS_ABI);
00369 #endif
00370 
00371   PRInt32 i = 0;
00372   do {
00373     nsCAutoString buf("Extension");
00374     buf.AppendInt(i++);
00375 
00376     nsCAutoString path;
00377     rv = parser.GetString(aSection, buf.get(), path);
00378     if (NS_FAILED(rv))
00379       break;
00380 
00381     nsCOMPtr<nsILocalFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
00382     if (NS_FAILED(rv))
00383       continue;
00384 
00385     nsCOMPtr<nsIFile> platformDir;
00386 #ifdef TARGET_OS_ABI
00387     nsCOMPtr<nsIFile> platformABIDir;
00388 #endif
00389     rv = dir->SetPersistentDescriptor(path);
00390     if (NS_FAILED(rv))
00391       continue;
00392 
00393     rv = dir->Clone(getter_AddRefs(platformDir));
00394     if (NS_FAILED(rv))
00395       continue;
00396 
00397     platformDir->AppendNative(platform);
00398     platformDir->AppendNative(osTarget);
00399 
00400 #ifdef TARGET_OS_ABI
00401     rv = dir->Clone(getter_AddRefs(platformABIDir));
00402     if (NS_FAILED(rv))
00403       continue;
00404 
00405     platformABIDir->AppendNative(platform);
00406     platformABIDir->AppendNative(targetOSABI);
00407 #endif
00408 
00409     const char* const* a = aAppendList;
00410     while (*a) {
00411       nsDependentCString directory(*a);
00412       dir->AppendNative(directory);
00413       platformDir->AppendNative(directory);
00414 #ifdef TARGET_OS_ABI
00415       platformABIDir->AppendNative(directory);
00416 #endif
00417       ++a;
00418     }
00419 
00420     PRBool exists;
00421     rv = dir->Exists(&exists);
00422     if (NS_SUCCEEDED(rv) && exists)
00423       aDirectories.AppendObject(dir);
00424 
00425     rv = platformDir->Exists(&exists);
00426     if (NS_SUCCEEDED(rv) && exists)
00427       aDirectories.AppendObject(platformDir);
00428 
00429 #ifdef TARGET_OS_ABI
00430     rv = platformABIDir->Exists(&exists);
00431     if (NS_SUCCEEDED(rv) && exists)
00432       aDirectories.AppendObject(platformABIDir);
00433 #endif
00434   }
00435   while (PR_TRUE);
00436 }
00437 
00438 static const char *const kAppendChromeManifests[] =
00439   { "chrome.manifest", nsnull };
00440 
00441 NS_IMETHODIMP
00442 nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
00443 {
00444   nsresult rv = NS_OK;
00445   *aResult = nsnull;
00446 
00447   nsCOMPtr<nsIFile> profileFile;
00448   if (mProfileDir) {
00449     mProfileDir->Clone(getter_AddRefs(profileFile));
00450     profileFile->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
00451   }
00452 
00453   if (!strcmp(aProperty, XRE_EXTENSIONS_DIR_LIST)) {
00454     nsCOMArray<nsIFile> directories;
00455     
00456     if (mProfileDir && !gSafeMode) {
00457       static const char *const kAppendNothing[] = { nsnull };
00458 
00459       LoadDirsIntoArray(profileFile, "ExtensionDirs",
00460                         kAppendNothing, directories);
00461     }
00462 
00463     rv = NS_NewArrayEnumerator(aResult, directories);
00464   }
00465   else if (!strcmp(aProperty, NS_XPCOM_COMPONENT_DIR_LIST)) {
00466     nsCOMArray<nsIFile> directories;
00467 
00468     if (mXULAppDir) {
00469       nsCOMPtr<nsIFile> file;
00470       mXULAppDir->Clone(getter_AddRefs(file));
00471       file->AppendNative(NS_LITERAL_CSTRING("components"));
00472       PRBool exists;
00473       if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
00474         directories.AppendObject(file);
00475     }
00476 
00477     if (mProfileDir && !gSafeMode) {
00478       static const char *const kAppendCompDir[] = { "components", nsnull };
00479 
00480       LoadDirsIntoArray(profileFile, "ExtensionDirs",
00481                         kAppendCompDir, directories);
00482     }
00483 
00484     rv = NS_NewArrayEnumerator(aResult, directories);
00485   }
00486   else if (!strcmp(aProperty, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
00487     nsCOMArray<nsIFile> directories;
00488     PRBool exists;
00489 
00490     if (mXULAppDir) {
00491       nsCOMPtr<nsIFile> file;
00492       mXULAppDir->Clone(getter_AddRefs(file));
00493       file->AppendNative(NS_LITERAL_CSTRING("defaults"));
00494       file->AppendNative(NS_LITERAL_CSTRING("preferences"));
00495       if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
00496         directories.AppendObject(file);
00497     }
00498     
00499     if (mProfileDir) {
00500       nsCOMPtr<nsIFile> overrideFile;
00501       mProfileDir->Clone(getter_AddRefs(overrideFile));
00502       overrideFile->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
00503       if (NS_SUCCEEDED(overrideFile->Exists(&exists)) && exists)
00504         directories.AppendObject(overrideFile);
00505 
00506       if (!gSafeMode) {
00507         static const char *const kAppendPrefDir[] = { "defaults", "preferences", nsnull };
00508 
00509         LoadDirsIntoArray(profileFile, "ExtensionDirs",
00510                           kAppendPrefDir, directories);
00511       }
00512     }
00513 
00514     rv = NS_NewArrayEnumerator(aResult, directories);
00515   }
00516   else if (!strcmp(aProperty, NS_CHROME_MANIFESTS_FILE_LIST)) {
00517     nsCOMArray<nsIFile> manifests;
00518 
00519     nsCOMPtr<nsIFile> manifest;
00520     mAppDir->Clone(getter_AddRefs(manifest));
00521     manifest->AppendNative(NS_LITERAL_CSTRING("chrome"));
00522     manifests.AppendObject(manifest);
00523 
00524     if (mXULAppDir) {
00525       nsCOMPtr<nsIFile> file;
00526       mXULAppDir->Clone(getter_AddRefs(file));
00527       file->AppendNative(NS_LITERAL_CSTRING("chrome"));
00528       PRBool exists;
00529       if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
00530         manifests.AppendObject(file);
00531 
00532       mXULAppDir->Clone(getter_AddRefs(file));
00533       file->AppendNative(NS_LITERAL_CSTRING("chrome.manifest"));
00534       if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
00535         manifests.AppendObject(file);
00536     }
00537 
00538     if (mProfileDir && !gSafeMode) {
00539       LoadDirsIntoArray(profileFile, "ExtensionDirs",
00540                         kAppendChromeManifests, manifests);
00541     }
00542 
00543     rv = NS_NewArrayEnumerator(aResult, manifests);
00544   }  
00545   else if (!strcmp(aProperty, NS_SKIN_MANIFESTS_FILE_LIST)) {
00546     nsCOMArray<nsIFile> manifests;
00547     if (mProfileDir && !gSafeMode) {
00548       LoadDirsIntoArray(profileFile, "ThemeDirs",
00549                         kAppendChromeManifests, manifests);
00550     }
00551 
00552     rv = NS_NewArrayEnumerator(aResult, manifests);
00553   }
00554   else if (!strcmp(aProperty, NS_APP_CHROME_DIR_LIST)) {
00555     // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
00556     // for OS window decoration.
00557 
00558     nsCOMArray<nsIFile> directories;
00559 
00560     if (mXULAppDir) {
00561       nsCOMPtr<nsIFile> file;
00562       mXULAppDir->Clone(getter_AddRefs(file));
00563       file->AppendNative(NS_LITERAL_CSTRING("chrome"));
00564       PRBool exists;
00565       if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
00566         directories.AppendObject(file);
00567     }
00568 
00569     if (mProfileDir && !gSafeMode) {
00570       static const char *const kAppendChromeDir[] = { "chrome", nsnull };
00571 
00572       LoadDirsIntoArray(profileFile, "ExtensionDirs",
00573                         kAppendChromeDir, directories);
00574     }
00575 
00576     rv = NS_NewArrayEnumerator(aResult, directories);
00577   }
00578   else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
00579     nsCOMArray<nsIFile> directories;
00580 
00581     // The root dirserviceprovider does quite a bit for us: we're mainly
00582     // interested in xulapp and extension-provided plugins.
00583     if (mXULAppDir) {
00584       nsCOMPtr<nsIFile> file;
00585       mXULAppDir->Clone(getter_AddRefs(file));
00586       file->AppendNative(NS_LITERAL_CSTRING("plugins"));
00587       PRBool exists;
00588       if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
00589         directories.AppendObject(file);
00590     }
00591 
00592     if (mProfileDir && !gSafeMode) {
00593       static const char *const kAppendPlugins[] = { "plugins", nsnull };
00594 
00595       LoadDirsIntoArray(profileFile, "ExtensionDirs",
00596                         kAppendPlugins, directories);
00597     }
00598 
00599     rv = NS_NewArrayEnumerator(aResult, directories);
00600     NS_ENSURE_SUCCESS(rv, rv);
00601 
00602     rv = NS_SUCCESS_AGGREGATE_RESULT;
00603   }
00604   else
00605     rv = NS_ERROR_FAILURE;
00606 
00607   return rv;
00608 }
00609 
00610 NS_IMETHODIMP
00611 nsXREDirProvider::GetDirectory(nsIFile* *aResult)
00612 {
00613   NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
00614 
00615   return mProfileDir->Clone(aResult);
00616 }
00617 
00618 NS_IMETHODIMP
00619 nsXREDirProvider::DoStartup()
00620 {
00621   if (!mProfileNotified) {
00622     nsCOMPtr<nsIObserverService> obsSvc
00623       (do_GetService("@mozilla.org/observer-service;1"));
00624     if (!obsSvc) return NS_ERROR_FAILURE;
00625 
00626     mProfileNotified = PR_TRUE;
00627 
00628     static const PRUnichar kStartup[] = {'s','t','a','r','t','u','p','\0'};
00629     obsSvc->NotifyObservers(nsnull, "profile-do-change", kStartup);
00630     obsSvc->NotifyObservers(nsnull, "profile-after-change", kStartup);
00631   }
00632   return NS_OK;
00633 }
00634 
00635 class ProfileChangeStatusImpl : public nsIProfileChangeStatus
00636 {
00637 public:
00638   NS_DECL_ISUPPORTS
00639   NS_DECL_NSIPROFILECHANGESTATUS
00640   ProfileChangeStatusImpl() { }
00641 private:
00642   ~ProfileChangeStatusImpl() { }
00643 };
00644 
00645 NS_IMPL_ISUPPORTS1(ProfileChangeStatusImpl, nsIProfileChangeStatus)
00646 
00647 NS_IMETHODIMP
00648 ProfileChangeStatusImpl::VetoChange()
00649 {
00650   NS_ERROR("Can't veto change!");
00651   return NS_ERROR_FAILURE;
00652 }
00653 
00654 NS_IMETHODIMP
00655 ProfileChangeStatusImpl::ChangeFailed()
00656 {
00657   NS_ERROR("Profile change cancellation.");
00658   return NS_ERROR_FAILURE;
00659 }
00660 
00661 void
00662 nsXREDirProvider::DoShutdown()
00663 {
00664   if (mProfileNotified) {
00665     nsCOMPtr<nsIObserverService> obssvc
00666       (do_GetService("@mozilla.org/observer-service;1"));
00667     NS_ASSERTION(obssvc, "No observer service?");
00668     if (obssvc) {
00669       nsCOMPtr<nsIProfileChangeStatus> cs = new ProfileChangeStatusImpl();
00670       static const PRUnichar kShutdownPersist[] =
00671         {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
00672       obssvc->NotifyObservers(cs, "profile-change-net-teardown", kShutdownPersist);
00673       obssvc->NotifyObservers(cs, "profile-change-teardown", kShutdownPersist);
00674 
00675       // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
00676       // resources which are about to go away in "profile-before-change" are destroyed first.
00677       nsCOMPtr<nsIThreadJSContextStack> stack
00678         (do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
00679       if (stack)
00680       {
00681         JSContext *cx = nsnull;
00682         stack->GetSafeJSContext(&cx);
00683         if (cx)
00684           ::JS_GC(cx);
00685       }
00686 
00687       // Phase 3: Notify observers of a profile change
00688       obssvc->NotifyObservers(cs, "profile-before-change", kShutdownPersist);
00689     }
00690     mProfileNotified = PR_FALSE;
00691   }
00692 }
00693 
00694 static void 
00695 GetProfileFolderName(char* aProfileFolderName, const char* aSource)
00696 {
00697   const char* reading = aSource;
00698 
00699   while (*reading) {
00700     *aProfileFolderName = tolower(*reading);
00701     ++aProfileFolderName; ++reading;
00702   }
00703   *aProfileFolderName = '\0';
00704 }
00705 
00706 #ifdef XP_WIN
00707 static nsresult
00708 GetShellFolderPath(int folder, char result[MAXPATHLEN])
00709 {
00710   LPMALLOC pMalloc;
00711   LPITEMIDLIST pItemIDList = NULL;
00712 
00713   if (!SUCCEEDED(SHGetMalloc(&pMalloc)))
00714     return NS_ERROR_OUT_OF_MEMORY;
00715 
00716   nsresult rv;
00717   if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, folder, &pItemIDList)) &&
00718       SUCCEEDED(SHGetPathFromIDList(pItemIDList, result))) {
00719     rv = NS_OK;
00720   } else {
00721     rv = NS_ERROR_NOT_AVAILABLE;
00722   }
00723 
00724   if (pItemIDList)
00725     pMalloc->Free(pItemIDList);
00726   pMalloc->Release();
00727   return rv;
00728 }
00729 
00730 nsresult
00731 nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
00732 {
00733   nsCOMPtr<nsIFile> appDir = GetAppDir();
00734   nsCAutoString appPath;
00735   nsresult rv = appDir->GetNativePath(appPath);
00736   NS_ENSURE_SUCCESS(rv, rv);
00737 
00738   // AppDir may be a short path. Convert to long path to make sure
00739   // the consistency of the update folder location
00740   nsCString longPath;
00741   longPath.SetLength(MAXPATHLEN);
00742   char *buf = longPath.BeginWriting();
00743 
00744   DWORD (WINAPI *pGetLongPathName)(LPCTSTR, LPTSTR, DWORD);
00745   // GetLongPathName() is not present on WinNT 4.0
00746   *(FARPROC *)&pGetLongPathName =
00747    GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameA");
00748  
00749   if (pGetLongPathName) {
00750     DWORD len = pGetLongPathName(appPath.get(), buf, MAXPATHLEN);
00751     // Failing GetLongPathName() is not fatal.
00752     if (len <= 0 || len >= MAXPATHLEN)
00753       longPath.Assign(appPath);
00754     else
00755       longPath.SetLength(len);
00756   }
00757   else {
00758     longPath.Assign(appPath);
00759   }
00760 
00761   // Use <UserLocalDataDir>\updates<relative path to app dir from
00762   // Program Files> if app dir is under Program Files to avoid the
00763   // folder virtualization mess on Windows Vista
00764   char programFiles[MAXPATHLEN];
00765   rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, programFiles);
00766   NS_ENSURE_SUCCESS(rv, rv);
00767 
00768   PRUint32 programFilesLen = strlen(programFiles);
00769   programFiles[programFilesLen++] = '\\';
00770   programFiles[programFilesLen] = '\0';
00771 
00772   if (longPath.Length() < programFilesLen)
00773     return NS_ERROR_FAILURE;
00774 
00775   if (_strnicmp(programFiles, longPath.get(), programFilesLen) != 0)
00776     return NS_ERROR_FAILURE;
00777 
00778   nsCOMPtr<nsILocalFile> updRoot;
00779   rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
00780   NS_ENSURE_SUCCESS(rv, rv);
00781 
00782   rv = updRoot->AppendRelativeNativePath(Substring(longPath, programFilesLen));
00783   NS_ENSURE_SUCCESS(rv, rv);
00784 
00785   NS_ADDREF(*aResult = updRoot);
00786   return NS_OK;
00787 }
00788 #endif
00789 
00790 nsresult
00791 nsXREDirProvider::GetUserDataDirectory(nsILocalFile** aFile, PRBool aLocal)
00792 {
00793   NS_ASSERTION(gAppData, "gAppData not initialized!");
00794 
00795   // Copied from nsAppFileLocationProvider (more or less)
00796   nsresult rv;
00797   nsCOMPtr<nsILocalFile> localDir;
00798 
00799 #if defined(XP_MACOSX)
00800   FSRef fsRef;
00801   OSType folderType;
00802   if (aLocal) {
00803     folderType = kCachedDataFolderType;
00804   } else {
00805 #ifdef MOZ_THUNDERBIRD 
00806     folderType = kDomainLibraryFolderType;
00807 #else
00808     folderType = kApplicationSupportFolderType;
00809 #endif 
00810   }
00811   OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
00812   NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
00813 
00814   rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(localDir));
00815   NS_ENSURE_SUCCESS(rv, rv);
00816 
00817   nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
00818   NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
00819 
00820   rv = dirFileMac->InitWithFSRef(&fsRef);
00821   NS_ENSURE_SUCCESS(rv, rv);
00822 
00823   // Note that MacOS ignores the vendor when creating the profile hierarchy - all
00824   // application preferences directories live alongside one another in 
00825   // ~/Library/Application Support/
00826   rv = dirFileMac->AppendNative(nsDependentCString(gAppData->name));
00827   NS_ENSURE_SUCCESS(rv, rv);
00828 #elif defined(XP_WIN)
00829   char path[MAXPATHLEN];
00830 
00831   // CSIDL_LOCAL_APPDATA is only defined on newer versions of Windows.  If the
00832   // OS does not understand it, then we'll fallback to the regular APPDATA
00833   // location.  If neither is defined, then we fallback to the Windows folder.
00834 
00835   if (aLocal)
00836     rv = GetShellFolderPath(CSIDL_LOCAL_APPDATA, path);
00837   if (!aLocal || NS_FAILED(rv))
00838     rv = GetShellFolderPath(CSIDL_APPDATA, path);
00839 
00840   if (NS_FAILED(rv) && !GetWindowsDirectory(path, sizeof(path))) {
00841     NS_WARNING("Aaah, no windows directory!");
00842     return NS_ERROR_FAILURE;
00843   }
00844 
00845   rv = NS_NewNativeLocalFile(nsDependentCString(path),
00846                              PR_TRUE, getter_AddRefs(localDir));
00847   NS_ENSURE_SUCCESS(rv, rv);
00848 
00849   if (gAppData->vendor) {
00850     rv = localDir->AppendNative(nsDependentCString(gAppData->vendor));
00851     NS_ENSURE_SUCCESS(rv, rv);
00852   }
00853   rv = localDir->AppendNative(nsDependentCString(gAppData->name));
00854   NS_ENSURE_SUCCESS(rv, rv);
00855 
00856 #elif defined(XP_OS2)
00857 #if 0 /* For OS/2 we want to always use MOZILLA_HOME */
00858   // we want an environment variable of the form
00859   // FIREFOX_HOME, etc
00860   nsDependentCString envVar(nsDependentCString(gAppData->name));
00861   envVar.Append("_HOME");
00862   char *pHome = getenv(envVar.get());
00863 #endif
00864   char *pHome = getenv("MOZILLA_HOME");
00865   if (pHome && *pHome) {
00866     rv = NS_NewNativeLocalFile(nsDependentCString(pHome), PR_TRUE,
00867                                getter_AddRefs(localDir));
00868   } else {
00869     PPIB ppib;
00870     PTIB ptib;
00871     char appDir[CCHMAXPATH];
00872 
00873     DosGetInfoBlocks(&ptib, &ppib);
00874     DosQueryModuleName(ppib->pib_hmte, CCHMAXPATH, appDir);
00875     *strrchr(appDir, '\\') = '\0';
00876     rv = NS_NewNativeLocalFile(nsDependentCString(appDir), PR_TRUE, getter_AddRefs(localDir));
00877   }
00878   NS_ENSURE_SUCCESS(rv, rv);
00879 
00880   if (gAppData->vendor) {
00881     rv = localDir->AppendNative(nsDependentCString(gAppData->vendor));
00882     NS_ENSURE_SUCCESS(rv, rv);
00883   }
00884   rv = localDir->AppendNative(nsDependentCString(gAppData->name));
00885   NS_ENSURE_SUCCESS(rv, rv);
00886 
00887 #elif defined(XP_BEOS)
00888   char appDir[MAXPATHLEN];
00889   if (find_directory(B_USER_SETTINGS_DIRECTORY, NULL, true, appDir, MAXPATHLEN))
00890     return NS_ERROR_FAILURE;
00891 
00892   int len = strlen(appDir);
00893   appDir[len]   = '/';
00894   appDir[len+1] = '\0';
00895 
00896   rv = NS_NewNativeLocalFile(nsDependentCString(appDir), PR_TRUE,
00897                              getter_AddRefs(localDir));
00898   NS_ENSURE_SUCCESS(rv, rv);
00899 
00900   if (gAppData->vendor) {
00901     rv = localDir->AppendNative(nsDependentCString(gAppData->vendor));
00902     NS_ENSURE_SUCCESS(rv, rv);
00903   }
00904   rv = localDir->AppendNative(nsDependentCString(gAppData->name));
00905   NS_ENSURE_SUCCESS(rv, rv);
00906 
00907 #elif defined(XP_UNIX)
00908   const char* homeDir = getenv("HOME");
00909   if (!homeDir || !*homeDir)
00910     return NS_ERROR_FAILURE;
00911 
00912   rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), PR_TRUE,
00913                              getter_AddRefs(localDir));
00914   NS_ENSURE_SUCCESS(rv, rv);
00915  
00916   char* appNameFolder = nsnull;
00917   char profileFolderName[MAXPATHLEN] = ".";
00918  
00919   // Offset 1 for the outermost folder to make it hidden (i.e. using the ".")
00920   char* writing = profileFolderName + 1;
00921   if (gAppData->vendor) {
00922     GetProfileFolderName(writing, gAppData->vendor);
00923     
00924     rv = localDir->AppendNative(nsDependentCString(profileFolderName));
00925     NS_ENSURE_SUCCESS(rv, rv);
00926  
00927     char temp[MAXPATHLEN];
00928     GetProfileFolderName(temp, gAppData->name);
00929     appNameFolder = temp;
00930   }
00931   else {
00932     GetProfileFolderName(writing, gAppData->name);
00933     appNameFolder = profileFolderName;
00934   }
00935   rv = localDir->AppendNative(nsDependentCString(appNameFolder));
00936   NS_ENSURE_SUCCESS(rv, rv);
00937 #else
00938 #error dont_know_how_to_get_product_dir_on_your_platform
00939 #endif
00940 
00941 #ifdef DEBUG_jungshik
00942   nsCAutoString cwd;
00943   localDir->GetNativePath(cwd);
00944   printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
00945 #endif
00946   rv = EnsureDirectoryExists(localDir);
00947   NS_ENSURE_SUCCESS(rv, rv);
00948 
00949   *aFile = localDir;
00950   NS_ADDREF(*aFile);
00951   return NS_OK;
00952 }
00953 
00954 nsresult
00955 nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
00956 {
00957   PRBool exists;
00958   nsresult rv = aDirectory->Exists(&exists);
00959   NS_ENSURE_SUCCESS(rv, rv);
00960 #ifdef DEBUG_jungshik
00961   if (!exists) {
00962     nsCAutoString cwd;
00963     aDirectory->GetNativePath(cwd);
00964     printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd.get());
00965   }
00966 #endif
00967   if (!exists)
00968     rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
00969 #ifdef DEBUG_jungshik
00970   if (NS_FAILED(rv))
00971     NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
00972 #endif
00973 
00974   return rv;
00975 }
00976 
00977 void
00978 nsXREDirProvider::EnsureProfileFileExists(nsIFile *aFile)
00979 {
00980   nsresult rv;
00981   PRBool exists;
00982     
00983   rv = aFile->Exists(&exists);
00984   if (NS_FAILED(rv) || exists) return;
00985   
00986   nsCAutoString leafName;
00987   rv = aFile->GetNativeLeafName(leafName);
00988   if (NS_FAILED(rv)) return;
00989 
00990   nsCOMPtr<nsIFile> defaultsFile;
00991   rv = GetProfileDefaultsDir(getter_AddRefs(defaultsFile));
00992   if (NS_FAILED(rv)) return;
00993 
00994   rv = defaultsFile->AppendNative(leafName);
00995   if (NS_FAILED(rv)) return;
00996   
00997   defaultsFile->CopyToNative(mProfileDir, EmptyCString());
00998 }
00999 
01000 nsresult
01001 nsXREDirProvider::GetProfileDefaultsDir(nsIFile* *aResult)
01002 {
01003   NS_ASSERTION(mAppDir, "nsXREDirProvider not initialized.");
01004   NS_PRECONDITION(aResult, "Null out-param");
01005 
01006   nsresult rv;
01007   nsCOMPtr<nsIFile> defaultsDir;
01008 
01009   rv = mAppDir->Clone(getter_AddRefs(defaultsDir));
01010   NS_ENSURE_SUCCESS(rv, rv);
01011 
01012   rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("defaults"));
01013   rv |= defaultsDir->AppendNative(NS_LITERAL_CSTRING("profile"));
01014   NS_ENSURE_SUCCESS(rv, rv);
01015 
01016   NS_ADDREF(*aResult = defaultsDir);
01017   return NS_OK;
01018 }
01019