Bug 756131 - API for creating default profiles for webapps, r=benjamin

This commit is contained in:
Olli Pettay 2012-05-24 17:29:52 +03:00
Родитель 57be59069b
Коммит 949bd03217
4 изменённых файлов: 283 добавлений и 68 удалений

Просмотреть файл

@ -6,11 +6,12 @@
#include "nsISupports.idl"
interface nsISimpleEnumerator;
interface nsIFile;
interface nsILocalFile;
interface nsIToolkitProfile;
interface nsIProfileLock;
[scriptable, uuid(9b434f48-438c-4f85-89de-b7f321a45341)]
[scriptable, uuid(b619f83d-8317-473c-b342-67905993fdc7)]
interface nsIToolkitProfileService : nsISupports
{
attribute boolean startWithLastProfile;
@ -52,6 +53,35 @@ interface nsIToolkitProfileService : nsISupports
in nsILocalFile aTempDir,
in AUTF8String aName);
/**
* Create the default profile for an application.
*
* The profile will be typically in
* {Application Data}/.profilename/{salt}.default or
* {Application Data}/.appname/{salt}.default
* or if aVendorName is provided
* {Application Data}/.vendor/appname/{salt}.default
*
* @note Either aProfileName or aAppName must be non-empty
*
* The contents of aProfileDefaultsDir will be copied to the
* new profile directory.
*
* @param aProfileName
* The name of the profile
* @param aAppName
* The name of the application
* @param aVendorName
* The name of the vendor
* @param aProfileDefaultsDir
* The location where the profile defaults are.
* @return The created profile.
*/
nsIToolkitProfile createDefaultProfileForApp(in AUTF8String aProfileName,
in AUTF8String aAppName,
in AUTF8String aVendorName,
[optional] in nsIFile aProfileDefaultsDir);
/**
* Returns the number of profiles.
* @return 0, 1, or 2. More than 2 profiles will always return 2.

Просмотреть файл

@ -56,7 +56,8 @@ private:
nsToolkitProfile(const nsACString& aName,
nsILocalFile* aRootDir,
nsILocalFile* aLocalDir,
nsToolkitProfile* aPrev);
nsToolkitProfile* aPrev,
bool aForExternalApp);
friend class nsToolkitProfileLock;
@ -64,6 +65,7 @@ private:
nsCOMPtr<nsILocalFile> mRootDir;
nsCOMPtr<nsILocalFile> mLocalDir;
nsIProfileLock* mLock;
bool mForExternalApp;
};
class nsToolkitProfileLock : public nsIProfileLock
@ -119,6 +121,16 @@ private:
NS_HIDDEN_(nsresult) Init();
nsresult CreateProfileInternal(nsILocalFile* aRootDir,
nsILocalFile* aLocalDir,
const nsACString& aName,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName,
/*in*/ nsIFile** aProfileDefaultsDir,
bool aForExternalApp,
nsIToolkitProfile** aResult);
nsRefPtr<nsToolkitProfile> mFirst;
nsCOMPtr<nsIToolkitProfile> mChosen;
nsCOMPtr<nsILocalFile> mAppData;
@ -147,19 +159,24 @@ private:
nsToolkitProfile::nsToolkitProfile(const nsACString& aName,
nsILocalFile* aRootDir,
nsILocalFile* aLocalDir,
nsToolkitProfile* aPrev) :
nsToolkitProfile* aPrev,
bool aForExternalApp) :
mPrev(aPrev),
mName(aName),
mRootDir(aRootDir),
mLocalDir(aLocalDir),
mLock(nsnull)
mLock(nsnull),
mForExternalApp(aForExternalApp)
{
NS_ASSERTION(aRootDir, "No file!");
if (aPrev)
aPrev->mNext = this;
else
nsToolkitProfileService::gService->mFirst = this;
if (!aForExternalApp) {
if (aPrev) {
aPrev->mNext = this;
} else {
nsToolkitProfileService::gService->mFirst = this;
}
}
}
NS_IMPL_ISUPPORTS1(nsToolkitProfile, nsIToolkitProfile)
@ -190,6 +207,7 @@ nsToolkitProfile::SetName(const nsACString& aName)
{
NS_ASSERTION(nsToolkitProfileService::gService,
"Where did my service go?");
NS_ENSURE_TRUE(!mForExternalApp, NS_ERROR_NOT_IMPLEMENTED);
mName = aName;
nsToolkitProfileService::gService->mDirty = true;
@ -203,6 +221,8 @@ nsToolkitProfile::Remove(bool removeFiles)
NS_ASSERTION(nsToolkitProfileService::gService,
"Whoa, my service is gone.");
NS_ENSURE_TRUE(!mForExternalApp, NS_ERROR_NOT_IMPLEMENTED);
if (mLock)
return NS_ERROR_FILE_IS_LOCKED;
@ -447,7 +467,7 @@ nsToolkitProfileService::Init()
currentProfile = new nsToolkitProfile(buffer,
rootDir, localDir,
currentProfile);
currentProfile, false);
NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
rv = parser.GetString(profileID.get(), "Default", buffer);
@ -606,25 +626,111 @@ static void SaltProfileName(nsACString& aName)
aName.Insert(salt, 0, 9);
}
NS_IMETHODIMP
nsToolkitProfileService::CreateDefaultProfileForApp(const nsACString& aProfileName,
const nsACString& aAppName,
const nsACString& aVendorName,
nsIFile* aProfileDefaultsDir,
nsIToolkitProfile** aResult)
{
NS_ENSURE_STATE(!aProfileName.IsEmpty() || !aAppName.IsEmpty());
nsCOMPtr<nsILocalFile> appData;
nsresult rv =
gDirServiceProvider->GetUserDataDirectory(getter_AddRefs(appData),
false,
&aProfileName,
&aAppName,
&aVendorName);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> profilesini;
appData->Clone(getter_AddRefs(profilesini));
rv = profilesini->AppendNative(NS_LITERAL_CSTRING("profiles.ini"));
NS_ENSURE_SUCCESS(rv, rv);
bool exists = false;
profilesini->Exists(&exists);
NS_ENSURE_FALSE(exists, NS_ERROR_ALREADY_INITIALIZED);
nsIFile* profileDefaultsDir = aProfileDefaultsDir;
rv = CreateProfileInternal(nsnull, nsnull,
NS_LITERAL_CSTRING("default"),
&aProfileName, &aAppName, &aVendorName,
&profileDefaultsDir, true, aResult);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(*aResult);
nsCOMPtr<nsILocalFile> rootDir;
(*aResult)->GetRootDir(getter_AddRefs(rootDir));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString profileDir;
rv = rootDir->GetRelativeDescriptor(appData, profileDir);
NS_ENSURE_SUCCESS(rv, rv);
nsCString ini;
ini.SetCapacity(512);
ini.AppendASCII("[General]\n");
ini.AppendASCII("StartWithLastProfile=1\n\n");
ini.AppendASCII("[Profile0]\n");
ini.AppendASCII("Name=default\n");
ini.AppendASCII("IsRelative=1\n");
ini.AppendASCII("Path=");
ini.Append(profileDir);
ini.AppendASCII("\n");
ini.AppendASCII("Default=1\n\n");
FILE* writeFile;
rv = profilesini->OpenANSIFileDesc("w", &writeFile);
NS_ENSURE_SUCCESS(rv, rv);
if (fwrite(ini.get(), sizeof(char), ini.Length(), writeFile) !=
ini.Length()) {
rv = NS_ERROR_UNEXPECTED;
}
fclose(writeFile);
return rv;
}
NS_IMETHODIMP
nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
nsILocalFile* aLocalDir,
const nsACString& aName,
nsIToolkitProfile* *aResult)
nsIToolkitProfile** aResult)
{
nsresult rv;
return CreateProfileInternal(aRootDir, aLocalDir, aName,
nsnull, nsnull, nsnull, nsnull, false, aResult);
}
rv = GetProfileByName(aName, aResult);
if (NS_SUCCEEDED(rv)) return rv;
nsresult
nsToolkitProfileService::CreateProfileInternal(nsILocalFile* aRootDir,
nsILocalFile* aLocalDir,
const nsACString& aName,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName,
nsIFile** aProfileDefaultsDir,
bool aForExternalApp,
nsIToolkitProfile** aResult)
{
nsresult rv = NS_ERROR_FAILURE;
if (!aForExternalApp) {
rv = GetProfileByName(aName, aResult);
if (NS_SUCCEEDED(rv)) {
return rv;
}
}
nsCOMPtr<nsILocalFile> rootDir (aRootDir);
nsCAutoString dirName;
if (!rootDir) {
nsCOMPtr<nsIFile> file;
bool dummy;
rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_ROOT_DIR, &dummy,
getter_AddRefs(file));
rv = gDirServiceProvider->GetUserProfilesRootDir(getter_AddRefs(file),
aProfileName, aAppName,
aVendorName);
NS_ENSURE_SUCCESS(rv, rv);
rootDir = do_QueryInterface(file);
@ -649,8 +755,10 @@ nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
else {
nsCOMPtr<nsIFile> file;
bool dummy;
rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_LOCAL_ROOT_DIR,
&dummy, getter_AddRefs(file));
rv = gDirServiceProvider->GetUserProfilesLocalDir(getter_AddRefs(file),
aProfileName,
aAppName,
aVendorName);
NS_ENSURE_SUCCESS(rv, rv);
localDir = do_QueryInterface(file);
@ -687,14 +795,18 @@ nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
rv = rootDir->GetLeafName(profileDirName);
NS_ENSURE_SUCCESS(rv, rv);
bool dummy;
rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy,
getter_AddRefs(profileDefaultsDir));
if (aProfileDefaultsDir) {
profileDefaultsDir = *aProfileDefaultsDir;
} else {
bool dummy;
rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy,
getter_AddRefs(profileDefaultsDir));
}
if (NS_SUCCEEDED(rv))
if (NS_SUCCEEDED(rv) && profileDefaultsDir)
rv = profileDefaultsDir->CopyTo(profileDirParent,
profileDirName);
if (NS_FAILED(rv)) {
if (NS_FAILED(rv) || !profileDefaultsDir) {
// if copying failed, lets just ensure that the profile directory exists.
rv = rootDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
NS_ENSURE_SUCCESS(rv, rv);
@ -714,14 +826,14 @@ nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
NS_ENSURE_SUCCESS(rv, rv);
}
nsToolkitProfile* last = mFirst;
nsToolkitProfile* last = aForExternalApp ? nsnull : mFirst;
if (last) {
while (last->mNext)
last = last->mNext;
}
nsCOMPtr<nsIToolkitProfile> profile =
new nsToolkitProfile(aName, rootDir, localDir, last);
new nsToolkitProfile(aName, rootDir, localDir, last, aForExternalApp);
if (!profile) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult = profile);

Просмотреть файл

@ -155,6 +155,52 @@ nsXREDirProvider::Release()
return 0;
}
nsresult
nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName)
{
nsCOMPtr<nsIFile> file;
nsresult rv = GetUserDataDirectory((nsILocalFile**)(nsIFile**)
getter_AddRefs(file),
false,
aProfileName, aAppName, aVendorName);
if (NS_SUCCEEDED(rv)) {
#if !defined(XP_UNIX) || defined(XP_MACOSX)
rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
#endif
// We must create the profile directory here if it does not exist.
rv |= EnsureDirectoryExists(file);
}
file.swap(*aResult);
return rv;
}
nsresult
nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName)
{
nsCOMPtr<nsIFile> file;
nsresult rv = GetUserDataDirectory((nsILocalFile**)(nsIFile**)
getter_AddRefs(file),
true,
aProfileName, aAppName, aVendorName);
if (NS_SUCCEEDED(rv)) {
#if !defined(XP_UNIX) || defined(XP_MACOSX)
rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
#endif
// We must create the profile directory here if it does not exist.
rv |= EnsureDirectoryExists(file);
}
file.swap(*aResult);
return NS_OK;
}
NS_IMETHODIMP
nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
nsIFile** aFile)
@ -245,28 +291,10 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
}
else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
if (NS_SUCCEEDED(rv)) {
#if !defined(XP_UNIX) || defined(XP_MACOSX)
rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
#endif
// We must create the profile directory here if it does not exist.
rv |= EnsureDirectoryExists(file);
}
rv = GetUserProfilesRootDir(getter_AddRefs(file), nsnull, nsnull, nsnull);
}
else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
rv = GetUserLocalDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
if (NS_SUCCEEDED(rv)) {
#if !defined(XP_UNIX) || defined(XP_MACOSX)
rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
#endif
// We must create the profile directory here if it does not exist.
rv |= EnsureDirectoryExists(file);
}
rv = GetUserProfilesLocalDir(getter_AddRefs(file), nsnull, nsnull, nsnull);
}
else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE) && gArgv[0]) {
nsCOMPtr<nsILocalFile> lf;
@ -1166,13 +1194,16 @@ nsXREDirProvider::GetSystemExtensionsDirectory(nsILocalFile** aFile)
#endif
nsresult
nsXREDirProvider::GetUserDataDirectory(nsILocalFile** aFile, bool aLocal)
nsXREDirProvider::GetUserDataDirectory(nsILocalFile** aFile, bool aLocal,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName)
{
nsCOMPtr<nsILocalFile> localDir;
nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
NS_ENSURE_SUCCESS(rv, rv);
rv = AppendProfilePath(localDir);
rv = AppendProfilePath(localDir, aProfileName, aAppName, aVendorName);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef DEBUG_jungshik
@ -1290,37 +1321,58 @@ nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
nsresult
nsXREDirProvider::AppendProfilePath(nsIFile* aFile)
nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName)
{
NS_ASSERTION(aFile, "Null pointer!");
if (!gAppData) {
return NS_ERROR_FAILURE;
}
nsCAutoString profile;
nsCAutoString appName;
nsCAutoString vendor;
if (aProfileName && !aProfileName->IsEmpty()) {
profile = *aProfileName;
} else if (aAppName) {
appName = *aAppName;
if (aVendorName) {
vendor = *aVendorName;
}
} else if (gAppData->profile) {
profile = gAppData->profile;
} else {
appName = gAppData->name;
vendor = gAppData->vendor;
}
nsresult rv;
if (!gAppData)
return NS_ERROR_FAILURE;
#if defined (XP_MACOSX)
if (gAppData->profile) {
rv = AppendProfileString(aFile, gAppData->profile);
if (!profile.IsEmpty()) {
rv = AppendProfileString(aFile, profile.get());
}
else {
// Note that MacOS ignores the vendor when creating the profile hierarchy -
// all application preferences directories live alongside one another in
// ~/Library/Application Support/
rv = aFile->AppendNative(nsDependentCString(gAppData->name));
rv = aFile->AppendNative(appName);
}
NS_ENSURE_SUCCESS(rv, rv);
#elif defined(XP_WIN) || defined(XP_OS2)
if (gAppData->profile) {
rv = AppendProfileString(aFile, gAppData->profile);
if (!profile.IsEmpty()) {
rv = AppendProfileString(aFile, profile.get());
}
else {
if (gAppData->vendor) {
rv = aFile->AppendNative(nsDependentCString(gAppData->vendor));
if (!vendor.IsEmpty()) {
rv = aFile->AppendNative(vendor);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aFile->AppendNative(nsDependentCString(gAppData->name));
rv = aFile->AppendNative(appName);
}
NS_ENSURE_SUCCESS(rv, rv);
@ -1328,15 +1380,18 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile)
// The directory used for storing profiles
// The parent of this directory is set in GetUserDataDirectoryHome
// XXX: handle gAppData->profile properly
// XXXsmaug ...and the rest of the profile creation!
MOZ_ASSERT(!aAppName,
"Profile creation for external applications is not implemented!");
rv = aFile->AppendNative(nsDependentCString("mozilla"));
NS_ENSURE_SUCCESS(rv, rv);
#elif defined(XP_UNIX)
// Make it hidden (i.e. using the ".")
nsCAutoString folder(".");
if (gAppData->profile) {
if (!profile.IsEmpty()) {
// Skip any leading path characters
const char* profileStart = gAppData->profile;
const char* profileStart = profile.get();
while (*profileStart == '/' || *profileStart == '\\')
profileStart++;
@ -1351,8 +1406,8 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile)
rv = AppendProfileString(aFile, folder.BeginReading());
}
else {
if (gAppData->vendor) {
folder.Append(gAppData->vendor);
if (!vendor.IsEmpty()) {
folder.Append(vendor);
ToLowerCase(folder);
rv = aFile->AppendNative(folder);
@ -1361,7 +1416,7 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile)
folder.Truncate();
}
folder.Append(gAppData->name);
folder.Append(appName);
ToLowerCase(folder);
rv = aFile->AppendNative(folder);

Просмотреть файл

@ -36,6 +36,15 @@ public:
static nsXREDirProvider* GetSingleton();
nsresult GetUserProfilesRootDir(nsIFile** aResult,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName);
nsresult GetUserProfilesLocalDir(nsIFile** aResult,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName);
// We only set the profile dir, we don't ensure that it exists;
// that is the responsibility of the toolkit profile service.
// We also don't fire profile-changed notifications... that is
@ -47,12 +56,19 @@ public:
nsresult GetProfileDefaultsDir(nsIFile* *aResult);
static nsresult GetUserAppDataDirectory(nsILocalFile* *aFile) {
return GetUserDataDirectory(aFile, false);
return GetUserDataDirectory(aFile, false, nsnull, nsnull, nsnull);
}
static nsresult GetUserLocalDataDirectory(nsILocalFile* *aFile) {
return GetUserDataDirectory(aFile, true);
return GetUserDataDirectory(aFile, true, nsnull, nsnull, nsnull);
}
// By default GetUserDataDirectory gets profile path from gAppData,
// but that can be overridden by using aProfileName/aAppName/aVendorName.
static nsresult GetUserDataDirectory(nsILocalFile** aFile, bool aLocal,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName);
/* make sure you clone it, if you need to do stuff to it */
nsIFile* GetGREDir() { return mGREDir; }
nsIFile* GetAppDir() {
@ -84,7 +100,6 @@ public:
protected:
nsresult GetFilesInternal(const char* aProperty, nsISimpleEnumerator** aResult);
static nsresult GetUserDataDirectory(nsILocalFile* *aFile, bool aLocal);
static nsresult GetUserDataDirectoryHome(nsILocalFile* *aFile, bool aLocal);
static nsresult GetSysUserExtensionsDirectory(nsILocalFile* *aFile);
#if defined(XP_UNIX) || defined(XP_MACOSX)
@ -95,7 +110,10 @@ protected:
// Determine the profile path within the UAppData directory. This is different
// on every major platform.
static nsresult AppendProfilePath(nsIFile* aFile);
static nsresult AppendProfilePath(nsIFile* aFile,
const nsACString* aProfileName,
const nsACString* aAppName,
const nsACString* aVendorName);
static nsresult AppendSysUserExtensionPath(nsIFile* aFile);