Landing semi-single-profile on the trunk (merge from the AVIARY_1_0_20040515_BRANCH).

This commit is contained in:
bsmedberg%covad.net 2004-06-14 00:17:48 +00:00
Родитель 1d3271fb25
Коммит 4fb772d656
21 изменённых файлов: 2353 добавлений и 0 удалений

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

@ -0,0 +1,37 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = public src
# Use Qute for non-Phoenix apps
ifndef MOZ_PHOENIX
DIRS += skin
endif
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,224 @@
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Ben Goodger (30/09/99)
* Brant Gurganus (23/03/03)
* Stefan Borggraefe (17/10/03)
* Benjamin Smedberg <bsmedberg@covad.net> - 8-Apr-2004
*/
const C = Components.classes;
const I = Components.interfaces;
const ToolkitProfileService = "@mozilla.org/toolkit/profile-service;1";
var gProfileService;
var gProfileManagerBundle;
var gDefaultProfileParent;
var gOldProfileName;
// The directory where the profile will be created.
var gProfileRoot;
// Text node to display the location and name of the profile to create.
var gProfileDisplay;
// Called once when the wizard is opened.
function initWizard()
{
try {
gProfileService = C[ToolkitProfileService].getService(I.nsIToolkitProfileService);
gProfileManagerBundle = document.getElementById("bundle_profileManager");
var dirService = C["@mozilla.org/file/directory_service;1"].getService(I.nsIProperties);
gDefaultProfileParent = dirService.get("DefProfRt", I.nsIFile);
gOldProfileName = document.getElementById("profileName").value;
// Initialize the profile location display.
gProfileDisplay = document.getElementById("profileDisplay").firstChild;
setDisplayToDefaultFolder();
}
catch(e) {
window.close();
throw (e);
}
}
// Called every time the second wizard page is displayed.
function initSecondWizardPage()
{
var profileName = document.getElementById("profileName");
profileName.select();
profileName.focus();
// Initialize profile name validation.
checkCurrentInput(profileName.value);
}
function setDisplayToDefaultFolder()
{
var defaultProfileDir = gDefaultProfileParent.clone();
defaultProfileDir.append(document.getElementById("profileName").value);
gProfileRoot = defaultProfileDir;
document.getElementById("useDefault").disabled = true;
}
function updateProfileDisplay()
{
gProfileDisplay.data = gProfileRoot.path;
}
// Invoke a folder selection dialog for choosing the directory of profile storage.
function chooseProfileFolder()
{
var newProfileRoot;
var dirChooser = C["@mozilla.org/filepicker;1"].createInstance(I.nsIFilePicker);
dirChooser.init(window, gProfileManagerBundle.getString("chooseFolder"),
I.nsIFilePicker.modeGetFolder);
dirChooser.appendFilters(I.nsIFilePicker.filterAll);
dirChooser.show();
newProfileRoot = dirChooser.file;
// Disable the "Default Folder..." button when the default profile folder
// was selected manually in the File Picker.
// This is always false on Windows, until bug 221872 is fixed.
document.getElementById("useDefault").disabled =
(newProfileRoot.parent.equals(gDefaultProfileParent));
gProfileRoot = newProfileRoot;
updateProfileDisplay();
}
// Checks the current user input for validity and triggers an error message accordingly.
function checkCurrentInput(currentInput)
{
var finishButton = document.documentElement.getButton("finish");
var finishText = document.getElementById("finishText");
var canAdvance;
var errorMessage = checkProfileName(currentInput);
if (!errorMessage) {
finishText.className = "";
finishText.firstChild.data = gProfileManagerBundle.getString("profileFinishText");
canAdvance = true;
}
else {
finishText.className = "error";
finishText.firstChild.data = errorMessage;
canAdvance = false;
}
document.documentElement.canAdvance = canAdvance;
finishButton.disabled = !canAdvance;
updateProfileDisplay();
}
function updateProfileName(aNewName) {
checkCurrentInput(aNewName);
if (gProfileRoot.leafName == gOldProfileName) {
gProfileRoot.leafName = aNewName;
updateProfileDisplay();
}
gOldProfileName = aNewName;
}
// Checks whether the given string is a valid profile name.
// Returns an error message describing the error in the name or "" when it's valid.
function checkProfileName(profileNameToCheck)
{
// Check for emtpy profile name.
if (!/\S/.test(profileNameToCheck))
return gProfileManagerBundle.getString("profileNameEmpty");
// Check whether all characters in the profile name are allowed.
if (/([\\*:?<>|\/\"])/.test(profileNameToCheck))
return gProfileManagerBundle.getFormattedString("invalidChar", [RegExp.$1]);
// Check whether a profile with the same name already exists.
if (profileExists(profileNameToCheck))
return gProfileManagerBundle.getString("profileExists");
// profileNameToCheck is valid.
return "";
}
function profileExists(aName)
{
var profiles = gProfileService.profiles;
while (profiles.hasMoreElements()) {
var profile = profiles.getNext().QueryInterface(I.nsIToolkitProfile);
if (profile.name.toLowerCase() == aName.toLowerCase())
return true;
}
return false;
}
// Called when the first wizard page is shown.
function enableNextButton()
{
document.documentElement.canAdvance = true;
}
function onFinish()
{
var profileName = document.getElementById("profileName").value;
var profile;
// Create profile named profileName in profileRoot.
try {
profile = gProfileService.createProfile(gProfileRoot, profileName);
}
catch (e) {
var profileCreationFailed =
gProfileManagerBundle.getString("profileCreationFailed");
var profileCreationFailedTitle =
gProfileManagerBundle.getString("profileCreationFailedTitle");
var promptService = C["@mozilla.org/embedcomp/prompt-service;1"].
getService(I.nsIPromptService);
promptService.alert(window, profileCreationFailedTitle,
profileCreationFailed + "\n" + e);
return false;
}
// window.opener is false if the Create Profile Wizard was opened from the
// command line.
if (window.opener) {
// Add new profile to the list in the Profile Manager.
window.opener.CreateProfile(profile);
}
else {
// Use the newly created Profile.
var profileLock = profile.lock();
var dialogParams = window.arguments[0].QueryInterface(I.nsIDialogParamBlock);
dialogParams.objects.insertElementAt(profileLock, 0, false);
}
// Exit the wizard.
return true;
}

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

@ -0,0 +1,63 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE wizard [
<!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd">
%brandDTD;
<!ENTITY % profileDTD SYSTEM "chrome://mozapps/locale/profile/createProfileWizard.dtd">
%profileDTD;
]>
<wizard id="createProfileWizard"
title="&newprofile.title;"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onwizardfinish="return onFinish();"
onload="initWizard();"
style="&window.size;">
<stringbundle id="bundle_profileManager"
src="chrome://mozapps/locale/profile/profileSelection.properties"/>
<script type="application/x-javascript"
src="chrome://mozapps/content/profile/createProfileWizard.js"/>
<wizardpage id="explanation" onpageshow="enableNextButton();">
<description>&profileCreationExplanation_1.text;</description>
<description>&profileCreationExplanation_2.text;</description>
<description>&profileCreationExplanation_3.text;</description>
<spacer flex="1"/>
<description>&profileCreationExplanation_4.text;</description>
</wizardpage>
<wizardpage id="createProfile" onpageshow="initSecondWizardPage();">
<description>&profileCreationIntro.text;</description>
<label accesskey="&profilePrompt.accesskey;" control="ProfileName">&profilePrompt.label;</label>
<textbox id="profileName" value="&profileDefaultName;"
oninput="updateProfileName(this.value);"/>
<separator/>
<description>&profileDirExplanation.text;</description>
<vbox class="indent" flex="1" style="overflow: auto;">
<description id="profileDisplay">*</description>
</vbox>
<hbox>
<button label="&button.choosefolder.label;" oncommand="chooseProfileFolder();"
accesskey="&button.choosefolder.accesskey;"/>
<button id="useDefault" label="&button.usedefault.label;"
oncommand="setDisplayToDefaultFolder(); updateProfileDisplay();"
accesskey="&button.usedefault.accesskey;" disabled="true"/>
</hbox>
<separator/>
<description id="finishText">*</description>
</wizardpage>
</wizard>

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

@ -0,0 +1,257 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Ben Goodger (03/01/00)
* Seth Spitzer (28/10/99)
* Dan Veditz <dveditz@netscape.com>
* Benjamin Smedberg <bsmedberg@covad.net>
*/
const C = Components.classes;
const I = Components.interfaces;
const ToolkitProfileService = "@mozilla.org/toolkit/profile-service;1";
const PromptService = "@mozilla.org/embedcomp/prompt-service;1";
var gDialogParams;
var gProfileManagerBundle;
var gBrandBundle;
var gProfileService;
var gPromptService;
function startup()
{
try {
gDialogParams = window.arguments[0].
QueryInterface(I.nsIDialogParamBlock);
gProfileService = C[ToolkitProfileService].getService(I.nsIToolkitProfileService);
gProfileManagerBundle = document.getElementById("bundle_profileManager");
gBrandBundle = document.getElementById("bundle_brand");
gPromptService = C[PromptService].getService(I.nsIPromptService);
document.documentElement.centerWindowOnScreen();
var profilesElement = document.getElementById("profiles");
var profileList = gProfileService.profiles;
while (profileList.hasMoreElements()) {
var profile = profileList.getNext().QueryInterface(I.nsIToolkitProfile);
var listitem = profilesElement.appendItem(profile.name, "");
var tooltiptext =
gProfileManagerBundle.getFormattedString("profileTooltip", [profile.name, profile.rootDir.path]);
listitem.setAttribute("tooltiptext", tooltiptext);
listitem.setAttribute("class", "listitem-iconic");
listitem.profile = profile;
try {
if (profile === gProfileService.selectedProfile) {
profilesElement.selectedItem = listitem;
}
}
catch(e) { }
}
var autoSelectLastProfile = document.getElementById("autoSelectLastProfile");
autoSelectLastProfile.checked = gProfileService.startWithLastProfile;
profilesElement.focus();
}
catch(e) {
window.close();
throw (e);
}
}
function acceptDialog()
{
var appName = gBrandBundle.getString("brandShortName");
var profilesElement = document.getElementById("profiles");
var selectedProfile = profilesElement.selectedItem;
if (!selectedProfile) {
var pleaseSelectTitle = gProfileManagerBundle.getString("pleaseSelectTitle");
var pleaseSelect =
gProfileManagerBundle.getFormattedString("pleaseSelect", [appName]);
gPromptService.alert(window, pleaseSelectTitle, pleaseSelect);
return false;
}
var profileLock;
try {
profileLock = selectedProfile.profile.lock();
}
catch (e) {
var lockedTitle = gProfileManagerBundle.getString("profileLockedTitle");
var locked =
gProfileManagerBundle.getFormattedString("profileLocked", [appName, selectedProfile.profile.name]);
gPromptService.alert(window, lockedTitle, locked);
return false;
}
gDialogParams.objects.insertElementAt(profileLock.nsIProfileLock, 0, false);
var autoSelectLastProfile = document.getElementById("autoSelectLastProfile");
gProfileService.startWithLastProfile = autoSelectLastProfile.checked;
gProfileService.selectedProfile = selectedProfile.profile;
gProfileService.startOffline = document.getElementById("offlineState").checked;
gDialogParams.SetInt(0, 1);
return true;
}
// handle key event on listboxes
function onProfilesKey(aEvent)
{
switch( aEvent.keyCode )
{
case 46:
confirmDelete();
break;
case "VK_F2":
renameProfile();
break;
}
}
function onProfilesDblClick(aEvent)
{
if(aEvent.target.localName == "listitem")
document.documentElement.acceptDialog();
}
// invoke the createProfile Wizard
function CreateProfileWizard()
{
window.openDialog('chrome://mozapps/content/profile/createProfileWizard.xul',
'', 'centerscreen,chrome,modal,titlebar', gProfileService);
}
/**
* Called from createProfileWizard to update the display.
*/
function CreateProfile(aProfile)
{
var profilesElement = document.getElementById("profiles");
var listitem = profilesElement.appendItem(aProfile.name, "");
var tooltiptext =
gProfileManagerBundle.getFormattedString("profileTooltip", [aProfile.name, aProfile.rootDir.path]);
listitem.setAttribute("tooltiptext", tooltiptext);
listitem.setAttribute("class", "listitem-iconic");
listitem.profile = aProfile;
profilesElement.ensureElementIsVisible(listitem);
profilesElement.selectItem(listitem);
}
// rename the selected profile
function RenameProfile()
{
var profilesElement = document.getElementById("profiles");
var selectedItem = profilesElement.selectedItem;
if (!selectedItem) {
return false;
}
var selectedProfile = selectedItem.profile;
var oldName = selectedProfile.name;
var newName = {value: oldName};
var dialogTitle = gProfileManagerBundle.getString("renameProfileTitle");
var msg =
gProfileManagerBundle.getFormattedString("renameProfilePrompt", [oldName]);
if (gPromptService.prompt(window, dialogTitle, msg, newName, null, {value:0})) {
newName = newName.value;
// User hasn't changed the profile name. Treat as if cancel was pressed.
if (newName == oldName)
return false;
try {
selectedProfile.name = newName;
}
catch (e) {
var alTitle = gProfileManagerBundle.getString("profileNameInvalidTitle");
var alMsg = gProfileManagerBundle.getFormattedString("profileNameInvalid", [newName]);
gPromptService.alert(window, alTitle, alMsg);
return false;
}
selectedItem.label = newName;
var tooltiptext =
gProfileManagerBundle.getFormattedString("profileTooltip", [newName, aProfile.rootDir.path]);
listitem.setAttribute("tooltiptext", tooltiptext);
return true;
}
return false;
}
function ConfirmDelete()
{
var deleteButton = document.getElementById("delbutton");
var profileList = document.getElementById( "profiles" );
var selectedItem = profileList.selectedItem;
if (!selectedItem) {
return false;
}
var selectedProfile = selectedItem.profile;
var deleteFiles = false;
if (selectedProfile.rootDir.exists()) {
var dialogTitle = gProfileManagerBundle.getString("deleteTitle");
var dialogText =
gProfileManagerBundle.getFormattedString("deleteProfile",
[selectedProfile.rootDir.path]);
var buttonPressed = gPromptService.confirmEx(window, dialogTitle, dialogText,
(gPromptService.BUTTON_TITLE_IS_STRING * gPromptService.BUTTON_POS_0) +
(gPromptService.BUTTON_TITLE_CANCEL * gPromptService.BUTTON_POS_1) +
(gPromptService.BUTTON_TITLE_IS_STRING * gPromptService.BUTTON_POS_2),
gProfileManagerBundle.getString("dontDeleteFiles"),
null,
gProfileManagerBundle.getString("deleteFiles"),
null, {value:0});
if (buttonPressed == 1)
return false;
if (buttonPressed == 2)
deleteFiles = true;
}
selectedProfile.remove(deleteFiles);
selectedItem.parentNode.removeChild(selectedItem);
return true;
}

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

@ -0,0 +1,88 @@
<?xml version="1.0"?>
<!-- -*- Mode: SGML; indent-tabs-mode: nil; -*- -->
<!--
The contents of this file are subject to the Netscape Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is mozilla.org code.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998 Netscape Communications Corporation. All
Rights Reserved.
Contributors:
Code: Ben Goodger <ben@netscape.com>
Benjamin Smedberg <bsmedberg@covad.net>
UI Ideas: Matthew Thomas, Ben Gregory
-->
<?xml-stylesheet href="chrome://mozapps/skin/profile/profileSelection.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd">
%brandDTD;
<!ENTITY % profileDTD SYSTEM "chrome://mozapps/locale/profile/profileSelection.dtd">
%profileDTD;
]>
<dialog
id="profileWindow"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
class="non-resizable"
title="&windowtitle.label;"
orient="vertical"
buttons="accept,cancel"
style="width: 30em;"
onload="startup();"
ondialogaccept="return acceptDialog()"
buttonlabelaccept="&start.label;"
buttonlabelcancel="&exit.label;">
<stringbundle id="bundle_profileManager"
src="chrome://mozapps/locale/profile/profileSelection.properties"/>
<stringbundle id="bundle_brand"
src="chrome://global/locale/brand.properties"/>
<script type="application/x-javascript" src="chrome://mozapps/content/profile/profileSelection.js"/>
<description class="label">&pmDescription.label;</description>
<separator class="thin"/>
<hbox class="profile-box indent" flex="1">
<vbox id="managebuttons">
<button id="newbutton" label="&newButton.label;"
accesskey="&newButton.accesskey;" oncommand="CreateProfileWizard();"/>
<button id="renbutton" label="&renameButton.label;"
accesskey="&renameButton.accesskey;" oncommand="RenameProfile();"/>
<button id="delbutton" label="&deleteButton.label;"
accesskey="&deleteButton.accesskey;" oncommand="ConfirmDelete();"/>
</vbox>
<separator flex="1"/>
<vbox flex="1">
<listbox id="profiles" flex="1" rows="5" seltype="single"
ondblclick="onProfilesDblClick(event)"
onkeypress="onProfilesKey(event);">
</listbox>
<checkbox id="offlineState" label="&offlineState.label;" accesskey="&offlineState.accesskey;"/>
<checkbox id="autoSelectLastProfile" label="&autoSelect.label;"
accesskey="&autoSelect.accesskey;"/>
</vbox>
</hbox>
</dialog>

10
toolkit/profile/jar.mn Normal file
Просмотреть файл

@ -0,0 +1,10 @@
toolkit.jar:
content/mozapps/profile/createProfileWizard.js (content/createProfileWizard.js)
content/mozapps/profile/createProfileWizard.xul (content/createProfileWizard.xul)
content/mozapps/profile/profileSelection.js (content/profileSelection.js)
content/mozapps/profile/profileSelection.xul (content/profileSelection.xul)
en-US.jar:
locale/en-US/mozapps/profile/createProfileWizard.dtd (locale/createProfileWizard.dtd)
locale/en-US/mozapps/profile/profileSelection.properties (locale/profileSelection.properties)
locale/en-US/mozapps/profile/profileSelection.dtd (locale/profileSelection.dtd)

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

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

@ -0,0 +1,49 @@
<!-- -*- Mode: SGML; indent-tabs-mode: nil; -*- -->
<!--
The contents of this file are subject to the Netscape Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is mozilla.org code.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s):
Ben Goodger (28/10/99)
-->
<!ENTITY windowtitle.label "&brandShortName; - Choose User Profile">
<!ENTITY profilename.label "Profile Name:">
<!ENTITY start.label "Start &brandShortName;">
<!ENTITY exit.label "Exit">
<!ENTITY availprofiles.label "Available Profiles">
<!ENTITY newButton.label "Create Profile...">
<!ENTITY newButton.accesskey "C">
<!ENTITY renameButton.label "Rename Profile...">
<!ENTITY renameButton.accesskey "R">
<!ENTITY deleteButton.label "Delete Profile...">
<!ENTITY deleteButton.accesskey "D">
<!-- manager entities -->
<!ENTITY pmDescription.label "&brandShortName; stores information about your settings, preferences, and other user items in your user profile.">
<!ENTITY offlineState.label "Work offline">
<!ENTITY offlineState.accesskey "o">
<!ENTITY autoSelect.label "Don't ask at startup">
<!ENTITY autoSelect.accesskey "s">

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

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

@ -0,0 +1,53 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla Seamonkey bootstrap code.
#
# The Initial Developer of the Original Code is
# Benjamin Smedberg <bsmedberg@covad.net>
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = xulapp
XPIDL_MODULE = toolkitprofile
XPIDLSRCS = \
nsIProfileMigrator.idl \
nsIToolkitProfile.idl \
nsIToolkitProfileService.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is The Browser Profile Migrator.
*
* The Initial Developer of the Original Code is Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@bengoodger.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIFile;
/**
* Helper interface for nsIProfileMigrator.
*
* @provider Toolkit (Startup code)
* @client Application (Profile-migration code)
* @obtainable nsIProfileMigrator.migrate
*/
[scriptable, uuid(048e5ca1-0eb7-4bb1-a9a2-a36f7d4e0e3c)]
interface nsIProfileStartup : nsISupports
{
/**
* The root directory of the semi-current profile, during profile migration.
* After nsIProfileMigrator.migrate has returned, this object will not be
* useful.
*/
readonly attribute nsIFile directory;
/**
* Do profile-startup by setting NS_APP_USER_PROFILE_50_DIR in the directory
* service and notifying the profile-startup observer topics.
*/
void doStartup();
};
/**
* Migrate application settings from an outside source.
*
* @provider Application (Profile-migration code)
* @client Toolkit (Startup code)
* @obtainable service, contractid("@mozilla.org/toolkit/profile-migrator;1")
*/
[scriptable, uuid(24ce8b9d-b7ff-4279-aef4-26e158f03e34)]
interface nsIProfileMigrator : nsISupports
{
/**
* Import existing profile paths. When the app is started the first
* time, if there are no INI-style profiles, appstartup will call
* this method to import any registry- style profiles that may
* exist. When this method is called, there is no event queue
* service and this method should not attempt to use the network or
* show any GUI.
*
* @note You don't actually have to move the profile data. Just call
* nsIToolkitProfileService.create on the existing profile path(s).
*/
void import();
/**
* Do profile migration.
*
* When this method is called, a default profile has been created;
* XPCOM has been initialized such that compreg.dat is in the
* profile; the directory service does *not* return a key for
* NS_APP_USER_PROFILE_50_DIR or any of the keys depending on an active
* profile. To figure out the directory of the "current" profile, use
* aStartup.directory.
*
* If your migrator needs to access services that use the profile (to
* set profile prefs or bookmarks, for example), use aStartup.doStartup.
*
* The startup code ignores COM exceptions thrown from this method.
*/
void migrate(in nsIProfileStartup aStartup);
};
%{C++
#define NS_PROFILEMIGRATOR_CONTRACTID "@mozilla.org/toolkit/profile-migrator;1"
%}

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

@ -0,0 +1,63 @@
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the new Mozilla toolkit.
*
* The Initial Developer of the Original Code is
* Benjamin Smedberg <bsmedberg@covad.net>
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsILocalFile;
interface nsIToolkitProfile;
/**
* Hold on to a profile lock. Once you release the last reference to this
* interface, the profile lock is released.
*/
[scriptable, uuid(6f987826-e4dd-453d-bb66-a1e46088fced)]
interface nsIProfileLock : nsISupports
{
readonly attribute nsILocalFile directory;
void unlock();
};
[scriptable, uuid(87cea5c2-b9ed-44f9-8984-e75bc9f7134a)]
interface nsIToolkitProfile : nsISupports
{
readonly attribute nsILocalFile rootDir;
attribute AUTF8String name;
void remove(in boolean removeFiles);
nsIProfileLock lock();
};

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

@ -0,0 +1,93 @@
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the new Mozilla toolkit.
*
* The Initial Developer of the Original Code is
* Benjamin Smedberg <bsmedberg@covad.net>
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsISimpleEnumerator;
interface nsILocalFile;
interface nsIToolkitProfile;
interface nsIProfileLock;
[scriptable, uuid(9b434f48-438c-4f85-89de-b7f321a45341)]
interface nsIToolkitProfileService : nsISupports
{
attribute boolean startWithLastProfile;
attribute boolean startOffline;
readonly attribute nsISimpleEnumerator /*nsIToolkitProfile*/ profiles;
attribute nsIToolkitProfile selectedProfile;
/**
* Get a profile by name. This is mainly for use by the -P
* commandline flag.
*
* @param aName The profile name to find.
*/
nsIToolkitProfile getProfileByName(in AUTF8String aName);
/**
* Lock an arbitrary path as a profile. If the path does not exist, it
* will be created and the defaults copied from the application directory.
*/
nsIProfileLock lockProfilePath(in nsILocalFile aDirectory);
/**
* Create a new profile.
*
* @param rootDir The profile directory. May be null, in which case a suitable
* default will be chosen based on the profile name.
* @param name The profile name.
*/
nsIToolkitProfile createProfile(in nsILocalFile rootDir,
in AUTF8String name);
/**
* Returns the number of profiles.
* @return 0, 1, or 2. More than 2 profiles will always return 2.
*/
readonly attribute unsigned long profileCount;
/**
* Flush the profiles list file.
*/
void flush();
};
%{C++
#define NS_PROFILESERVICE_CONTRACTID "@mozilla.org/toolkit/profile-service;1"
%}

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

@ -0,0 +1,29 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,3 @@
classic.jar:
skin/classic/mozapps/profile/profileSelection.css
skin/classic/mozapps/profile/profileicon.png

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

@ -0,0 +1,52 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is new Mozilla XUL toolkit.
*
* The Initial Developer of the Original Code is
* Benjamin Smedberg <bsmedberg@covad.net>
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
@import url("chrome://global/skin/global.css");
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
#profiles > listitem {
list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
}
box#managebuttons > button {
min-width: 8em;
}
#managebuttons {
padding-top: 1em;
}

Двоичные данные
toolkit/profile/skin/profileicon.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 795 B

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

@ -0,0 +1,55 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = xulapp
LIBRARY_NAME = profile_s
FORCE_STATIC_LIB = 1
REQUIRES = \
xpcom \
string \
appcomps \
$(NULL)
LOCAL_INCLUDES = \
-I$(srcdir)/../../xre \
-I$(topsrcdir)/profile/dirserviceprovider/src \
$(NULL)
CPPSRCS = \
nsProfileLock.cpp \
nsToolkitProfileService.cpp \
nsINIParser.cpp \
$(NULL)
GARBAGE += nsProfileLock.cpp
include $(topsrcdir)/config/rules.mk
export:: $(topsrcdir)/profile/dirserviceprovider/src/nsProfileLock.cpp
$(INSTALL) $^ .

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

@ -0,0 +1,253 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code,
* released March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Samir Gehani <sgehani@netscape.com>
* Benjamin Smedberg <bsmedberg@covad.net>
*/
#include "nsINIParser.h"
#include "nsError.h"
#include "nsILocalFile.h"
#include <stdlib.h>
#include <stdio.h>
nsINIParser::nsINIParser() :
mFileBuf(nsnull),
mFileBufSize(0)
{ }
nsresult
nsINIParser::Init(nsILocalFile* aFile)
{
NS_ASSERTION(aFile, "Null param.");
nsresult rv;
FILE *fd;
long eofpos = 0;
int rd = 0;
/* open the file */
rv = aFile->OpenANSIFileDesc("r", &fd);
NS_ENSURE_SUCCESS(rv, rv);
/* get file size */
if (fseek(fd, 0, SEEK_END) != 0) {
rv = NS_BASE_STREAM_OSERROR;
goto bail;
}
eofpos = ftell(fd);
if (eofpos == 0) {
rv = NS_BASE_STREAM_OSERROR;
goto bail;
}
/* malloc an internal buf the size of the file */
mFileBuf = (char *) malloc((eofpos+1) * sizeof(char));
if (!mFileBuf) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto bail;
}
mFileBufSize = eofpos;
/* read the file in one swoop */
if (fseek(fd, 0, SEEK_SET) != 0) {
rv = NS_BASE_STREAM_OSERROR;
goto bail;
}
rd = fread((void *)mFileBuf, 1, eofpos, fd);
if (!rd) {
rv = NS_BASE_STREAM_OSERROR;
goto bail;
}
mFileBuf[mFileBufSize] = '\0';
/* close file */
fclose(fd);
return NS_OK;
bail:
if (fd)
fclose(fd);
if (mFileBuf) {
free(mFileBuf);
mFileBuf = nsnull;
}
return NS_ERROR_FAILURE;
}
nsINIParser::~nsINIParser()
{
if (mFileBuf) {
free(mFileBuf);
mFileBuf = nsnull;
}
}
nsresult
nsINIParser::GetString(const char *aSection, const char *aKey,
char *aValBuf, PRUint32 aIOValBufSize)
{
NS_ASSERTION(aSection && aKey && aValBuf && aIOValBufSize,
"Null param!");
nsresult rv;
char *secPtr;
/* find the section if it exists */
rv = FindSection(aSection, &secPtr);
if (NS_FAILED(rv)) return rv;
/* find the key if it exists in the valid section we found */
rv = FindKey(secPtr, aKey, aValBuf, aIOValBufSize);
return rv;
}
nsresult
nsINIParser::FindSection(const char *aSection, char **aOutSecPtr)
{
char *currChar = mFileBuf;
char *nextSec = nsnull;
char *secClose = nsnull;
char *nextNL = nsnull;
int aSectionLen = strlen(aSection);
nsresult rv = NS_ERROR_FAILURE;
while (currChar < (mFileBuf + mFileBufSize))
{
// look for first '['
nextSec = NULL;
nextSec = strchr(currChar, '[');
if (!nextSec)
break;
currChar = nextSec + 1;
// extract section name till first ']'
secClose = NULL; nextNL = NULL;
secClose = strchr(currChar, ']');
nextNL = strchr(currChar, '\n');
if ((!nextNL) || (nextNL < secClose))
{
currChar = nextNL;
continue;
}
// if section name matches we succeeded
if (strncmp(aSection, currChar, aSectionLen) == 0
&& secClose-currChar == aSectionLen)
{
*aOutSecPtr = secClose + 1;
rv = NS_OK;
break;
}
}
return rv;
}
nsresult
nsINIParser::FindKey(const char *aSecPtr, const char *aKey, char *aVal, int aIOValSize)
{
const char *nextNL = nsnull;
const char *secEnd = nsnull;
const char *currLine = aSecPtr;
const char *nextEq = nsnull;
int aKeyLen = strlen(aKey);
// determine the section end
secEnd = aSecPtr;
find_end:
if (secEnd)
secEnd = strchr(secEnd, '['); // search for next sec start
if (!secEnd)
{
secEnd = strchr(aSecPtr, '\0'); // else search for file end
if (!secEnd)
{
return NS_ERROR_FILE_CORRUPTED;
}
}
// handle start section token ('[') in values for i18n
if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == '\n'))
{
secEnd++;
goto find_end;
}
while (currLine < secEnd)
{
nextNL = NULL;
nextNL = strchr(currLine, '\n');
if (!nextNL)
nextNL = mFileBuf + mFileBufSize;
// ignore commented lines (starting with ;)
if (currLine == strchr(currLine, ';'))
{
currLine = nextNL + 1;
continue;
}
// extract key before '='
nextEq = NULL;
nextEq = strchr(currLine, '=');
if (!nextEq || nextEq > nextNL)
{
currLine = nextNL + 1;
continue;
}
// if key matches we succeeded
if (strncmp(currLine, aKey, aKeyLen) == 0
&& nextEq-currLine == aKeyLen)
{
// extract the value and return
if (aIOValSize < nextNL - nextEq)
{
*aVal = '\0';
return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
}
PRUint32 len = nextNL - (nextEq + 1);
// allows win32-style \r\n line endings
if ( *(nextEq + len) == '\r' )
--len;
strncpy(aVal, (nextEq + 1), len);
*(aVal + len) = 0; // null terminate
return NS_OK;
}
else
{
currLine = nextNL + 1;
}
}
return NS_ERROR_FAILURE;
}

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

@ -0,0 +1,96 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code,
* released March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Samir Gehani <sgehani@netscape.com>
* Benjamin Smedberg <bsmedberg@covad.net>
*
* This file was shamelessly copied from mozilla/xpinstall/wizard/unix/src2
*/
#ifndef nsINIParser_h__
#define nsINIParser_h__
#include "nscore.h"
// hack alert: in static builds, nsINIParser here conflicts with nsINIParser
// in browser/components/migration. So we use a #define to make the symbols
// unique.
#define nsINIParser nsINITParser
class nsILocalFile;
class nsINIParser
{
public:
nsINIParser();
~nsINIParser();
#if 0 // use nsresult instead
/**
* Errors
*/
enum INIResult
{
OK = 0,
E_READ = -701,
E_MEM = -702,
E_PARAM = -703,
E_NO_SEC = -704,
E_NO_KEY = -705,
E_SEC_CORRUPT = -706,
E_SMALL_BUF = -707
};
#endif
/**
* Initialize the INIParser with a nsILocalFile. If this method fails, no
* other methods should be called.
*/
nsresult Init(nsILocalFile* aFile);
/**
* GetString
*
* Gets the value of the specified key in the specified section
* of the INI file represented by this instance. The value is stored
* in the supplied buffer. The buffer size is provided as input and
* the actual bytes used by the value is set in the in/out size param.
*
* @param aSection section name
* @param aKey key name
* @param aValBuf user supplied buffer
* @param aIOValBufSize buf size on input; actual buf used on output
*
* @return mError operation success code
*/
nsresult GetString(const char *aSection, const char *aKey,
char *aValBuf, PRUint32 aIOValBufSize );
private:
nsresult FindSection(const char *aSection, char **aOutSecPtr);
nsresult FindKey(const char *aSecPtr, const char *aKey,
char *aVal, int aIOValSize);
char *mFileBuf;
int mFileBufSize;
};
#endif /* nsINIParser_h__ */

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

@ -0,0 +1,820 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the new Mozilla toolkit.
*
* The Initial Developer of the Original Code is
* Benjamin Smedberg <bsmedberg@covad.net>
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include <stdlib.h>
#include "nsProfileLock.h"
#ifdef XP_WIN
#include <windows.h>
#include <shlobj.h>
#endif
#ifdef XP_BEOS
#include <Path.h>
#endif
#ifdef XP_UNIX
#include <unistd.h>
#endif
#include "nsIToolkitProfileService.h"
#include "nsIToolkitProfile.h"
#include "nsIFactory.h"
#include "nsILocalFile.h"
#include "nsISimpleEnumerator.h"
#ifdef XP_MACOSX
#include <CFURL.h>
#include "nsILocalFileMac.h"
#endif
#include "nsAppDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "nsINIParser.h"
#include "nsXREDirProvider.h"
#include "nsAppRunner.h"
#include "nsString.h"
#include "nsReadableUtils.h"
class nsToolkitProfile : public nsIToolkitProfile
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITOOLKITPROFILE
friend class nsToolkitProfileService;
nsCOMPtr<nsToolkitProfile> mNext;
nsToolkitProfile *mPrev;
private:
nsToolkitProfile(const nsACString& aName, nsILocalFile* aFile,
nsToolkitProfile* aPrev);
~nsToolkitProfile() { }
friend class nsToolkitProfileLock;
nsCString mName;
nsCOMPtr<nsILocalFile> mFile;
nsIProfileLock* mLock;
};
class nsToolkitProfileLock : public nsIProfileLock
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROFILELOCK
nsresult Init(nsToolkitProfile* aProfile);
nsresult Init(nsILocalFile* aDirectory);
nsToolkitProfileLock() { }
private:
~nsToolkitProfileLock();
nsCOMPtr<nsToolkitProfile> mProfile;
nsCOMPtr<nsILocalFile> mDirectory;
nsProfileLock mLock;
};
class nsToolkitProfileService : public nsIToolkitProfileService,
public nsIFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITOOLKITPROFILESERVICE
// we implement nsIFactory because we can't be registered by location,
// like most ordinary components are. Instead, during startup we register
// our factory. Then we return our singleton-self when asked.
NS_DECL_NSIFACTORY
private:
friend class nsToolkitProfile;
friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**);
nsToolkitProfileService() :
mDirty(PR_FALSE),
mStartWithLast(PR_TRUE),
mStartOffline(PR_FALSE)
{
gService = this;
}
~nsToolkitProfileService()
{
gService = nsnull;
}
NS_HIDDEN_(nsresult) Init();
nsCOMPtr<nsToolkitProfile> mFirst;
nsCOMPtr<nsToolkitProfile> mChosen;
nsCOMPtr<nsILocalFile> mAppData;
nsCOMPtr<nsILocalFile> mListFile;
PRBool mDirty;
PRBool mStartWithLast;
PRBool mStartOffline;
static nsToolkitProfileService *gService;
class ProfileEnumerator : public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISIMPLEENUMERATOR
ProfileEnumerator(nsToolkitProfile *first)
{ mCurrent = first; }
private:
~ProfileEnumerator() { }
nsCOMPtr<nsToolkitProfile> mCurrent;
};
};
nsToolkitProfile::nsToolkitProfile(const nsACString& aName, nsILocalFile* aFile,
nsToolkitProfile* aPrev) :
mPrev(aPrev),
mName(aName),
mFile(aFile),
mLock(nsnull)
{
NS_ASSERTION(aFile, "No file!");
if (aPrev)
aPrev->mNext = this;
else
nsToolkitProfileService::gService->mFirst = this;
}
NS_IMPL_ISUPPORTS1(nsToolkitProfile, nsIToolkitProfile)
NS_IMETHODIMP
nsToolkitProfile::GetRootDir(nsILocalFile* *aResult)
{
NS_ADDREF(*aResult = mFile);
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfile::GetName(nsACString& aResult)
{
aResult = mName;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfile::SetName(const nsACString& aName)
{
NS_ASSERTION(nsToolkitProfileService::gService,
"Where did my service go?");
mName = aName;
nsToolkitProfileService::gService->mDirty = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfile::Remove(PRBool removeFiles)
{
NS_ASSERTION(nsToolkitProfileService::gService,
"Whoa, my service is gone.");
if (mLock)
return NS_ERROR_FILE_IS_LOCKED;
if (removeFiles)
mFile->Remove(PR_TRUE);
if (mPrev)
mPrev->mNext = mNext;
else
nsToolkitProfileService::gService->mFirst = mNext;
if (mNext)
mNext->mPrev = mPrev;
mPrev = nsnull;
mNext = nsnull;
if (nsToolkitProfileService::gService->mChosen == this)
nsToolkitProfileService::gService = nsnull;
nsToolkitProfileService::gService->mDirty = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfile::Lock(nsIProfileLock* *aResult)
{
if (mLock) {
NS_ADDREF(*aResult = mLock);
return NS_OK;
}
nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
if (!lock) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = lock->Init(this);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*aResult = lock);
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsToolkitProfileLock, nsIProfileLock)
nsresult
nsToolkitProfileLock::Init(nsToolkitProfile* aProfile)
{
nsresult rv;
rv = Init(aProfile->mFile);
if (NS_SUCCEEDED(rv))
mProfile = aProfile;
return rv;
}
nsresult
nsToolkitProfileLock::Init(nsILocalFile* aDirectory)
{
nsresult rv;
rv = mLock.Lock(aDirectory);
if (NS_SUCCEEDED(rv))
mDirectory = aDirectory;
return rv;
}
NS_IMETHODIMP
nsToolkitProfileLock::GetDirectory(nsILocalFile* *aResult)
{
if (!mDirectory) {
NS_ERROR("Not initialized, or unlocked!");
return NS_ERROR_NOT_INITIALIZED;
}
NS_ADDREF(*aResult = mDirectory);
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileLock::Unlock()
{
if (!mDirectory) {
NS_ERROR("Unlocking a never-locked nsToolkitProfileLock!");
return NS_ERROR_UNEXPECTED;
}
mLock.Unlock();
if (mProfile) {
mProfile->mLock = nsnull;
mProfile = nsnull;
}
mDirectory = nsnull;
return NS_OK;
}
nsToolkitProfileLock::~nsToolkitProfileLock()
{
if (mDirectory) {
Unlock();
}
}
nsToolkitProfileService*
nsToolkitProfileService::gService = nsnull;
NS_IMPL_ISUPPORTS2(nsToolkitProfileService,
nsIToolkitProfileService,
nsIFactory)
nsresult
nsToolkitProfileService::Init()
{
NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!");
nsresult rv;
rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> listFile;
rv = mAppData->Clone(getter_AddRefs(listFile));
NS_ENSURE_SUCCESS(rv, rv);
mListFile = do_QueryInterface(listFile);
NS_ENSURE_TRUE(listFile, NS_ERROR_NO_INTERFACE);
rv = mListFile->AppendNative(NS_LITERAL_CSTRING("profiles.ini"));
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
rv = mListFile->IsFile(&exists);
if (NS_FAILED(rv) || !exists) {
return NS_OK;
}
nsINIParser parser;
rv = parser.Init(mListFile);
// Parsing errors are troublesome... we're gonna continue even on
// parsing errors, and let people manually re-locate their profile
// if something goes wacky
char parserBuf[MAXPATHLEN];
rv = parser.GetString("General", "StartWithLastProfile", parserBuf, MAXPATHLEN);
if (NS_SUCCEEDED(rv) && strcmp("0", parserBuf) == 0)
mStartWithLast = PR_FALSE;
nsToolkitProfile* currentProfile = nsnull;
nsCAutoString filePath;
unsigned int c = 0;
for (c = 0; PR_TRUE; ++c) {
char profileID[12];
sprintf(profileID, "Profile%u", c);
rv = parser.GetString(profileID, "IsRelative", parserBuf, MAXPATHLEN);
if (NS_FAILED(rv)) break;
PRBool isRelative = (strcmp(parserBuf, "1") == 0);
rv = parser.GetString(profileID, "Path", parserBuf, MAXPATHLEN);
if (NS_FAILED(rv)) {
NS_ERROR("Malformed profiles.ini: Path= not found");
continue;
}
filePath = parserBuf;
rv = parser.GetString(profileID, "Name", parserBuf, MAXPATHLEN);
if (NS_FAILED(rv)) {
NS_ERROR("Malformed profiles.ini: Name= not found");
continue;
}
nsCOMPtr<nsILocalFile> rootDir;
rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE,
getter_AddRefs(rootDir));
NS_ENSURE_SUCCESS(rv, rv);
if (isRelative) {
rv = rootDir->SetRelativeDescriptor(mAppData, filePath);
} else {
rv = rootDir->SetPersistentDescriptor(filePath);
}
if (NS_FAILED(rv)) continue;
currentProfile = new nsToolkitProfile(nsDependentCString(parserBuf),
rootDir, currentProfile);
NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
rv = parser.GetString(profileID, "Default", parserBuf, MAXPATHLEN);
if (NS_SUCCEEDED(rv) && strcmp("1", parserBuf) == 0)
mChosen = currentProfile;
}
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::SetStartWithLastProfile(PRBool aValue)
{
if (mStartWithLast != aValue) {
mStartWithLast = aValue;
mDirty = PR_TRUE;
}
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::GetStartWithLastProfile(PRBool *aResult)
{
*aResult = mStartWithLast;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::GetStartOffline(PRBool *aResult)
{
*aResult = mStartOffline;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::SetStartOffline(PRBool aValue)
{
mStartOffline = aValue;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::GetProfiles(nsISimpleEnumerator* *aResult)
{
*aResult = new ProfileEnumerator(this->mFirst);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsToolkitProfileService::ProfileEnumerator,
nsISimpleEnumerator)
NS_IMETHODIMP
nsToolkitProfileService::ProfileEnumerator::HasMoreElements(PRBool* aResult)
{
*aResult = mCurrent ? PR_TRUE : PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::ProfileEnumerator::GetNext(nsISupports* *aResult)
{
if (!mCurrent) return NS_ERROR_FAILURE;
NS_ADDREF(*aResult = mCurrent);
mCurrent = mCurrent->mNext;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::GetSelectedProfile(nsIToolkitProfile* *aResult)
{
if (!mChosen && mFirst && !mFirst->mNext) // only one profile
mChosen = mFirst;
if (!mChosen) return NS_ERROR_FAILURE;
NS_ADDREF(*aResult = mChosen);
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::SetSelectedProfile(nsIToolkitProfile* aProfile)
{
if (mChosen != aProfile) {
mChosen = aProfile;
mDirty = PR_TRUE;
}
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::GetProfileByName(const nsACString& aName,
nsIToolkitProfile* *aResult)
{
nsToolkitProfile* curP = mFirst;
while (curP) {
if (curP->mName.Equals(aName)) {
NS_ADDREF(*aResult = curP);
return NS_OK;
}
curP = curP->mNext;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsToolkitProfileService::LockProfilePath(nsILocalFile* aDirectory,
nsIProfileLock* *aResult)
{
return NS_LockProfilePath(aDirectory, aResult);
}
nsresult
NS_LockProfilePath(nsILocalFile* aPath, nsIProfileLock* *aResult)
{
nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
if (!lock) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = lock->Init(aPath);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*aResult = lock);
return NS_OK;
}
static const char kTable[] =
{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
static void SaltProfileName(nsACString& aName)
{
double fpTime;
LL_L2D(fpTime, PR_Now());
// use 1e-6, granularity of PR_Now() on the mac is seconds
srand((uint)(fpTime * 1e-6 + 0.5));
aName.Append('.');
int i;
for (i = 0; i < 3; ++i)
aName.Append(kTable[rand() % NS_ARRAY_LENGTH(kTable)]);
}
NS_IMETHODIMP
nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
const nsACString& aName,
nsIToolkitProfile* *aResult)
{
nsresult rv;
rv = GetProfileByName(aName, aResult);
if (NS_SUCCEEDED(rv)) return rv;
nsCOMPtr<nsILocalFile> rootDir (aRootDir);
if (!rootDir) {
nsCOMPtr<nsIFile> file;
PRBool dummy;
rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_ROOT_DIR, &dummy,
getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
rootDir = do_QueryInterface(file);
NS_ENSURE_TRUE(rootDir, NS_ERROR_UNEXPECTED);
nsCAutoString dirName(aName);
SaltProfileName(dirName);
rootDir->AppendNative(dirName);
}
PRBool exists;
rv = rootDir->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
rv = rootDir->IsDirectory(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (!exists)
return NS_ERROR_FILE_NOT_DIRECTORY;
}
else {
nsCOMPtr<nsIFile> profileDefaultsDir;
nsCOMPtr<nsIFile> profileDirParent;
nsCAutoString profileDirName;
rv = rootDir->GetParent(getter_AddRefs(profileDirParent));
NS_ENSURE_SUCCESS(rv, rv);
rv = rootDir->GetNativeLeafName(profileDirName);
NS_ENSURE_SUCCESS(rv, rv);
PRBool dummy;
rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy,
getter_AddRefs(profileDefaultsDir));
if (NS_SUCCEEDED(rv))
rv = profileDefaultsDir->CopyToNative(profileDirParent,
profileDirName);
if (NS_FAILED(rv)) {
// if copying failed, lets just ensure that the profile directory exists.
rv = rootDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = rootDir->SetPermissions(0700);
NS_ENSURE_SUCCESS(rv, rv);
}
nsToolkitProfile* last = mFirst;
if (last) {
while (last->mNext)
last = last->mNext;
}
nsCOMPtr<nsIToolkitProfile> profile =
new nsToolkitProfile(aName, rootDir, last);
if (!profile) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult = profile);
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::GetProfileCount(PRUint32 *aResult)
{
if (!mFirst)
*aResult = 0;
else if (! mFirst->mNext)
*aResult = 1;
else
*aResult = 2;
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::Flush()
{
// Errors during writing might cause unhappy semi-written files.
// To avoid this, write the entire thing to a buffer, then write
// that buffer to disk.
nsresult rv;
PRUint32 pCount = 0;
nsToolkitProfile *cur;
for (cur = mFirst; cur != nsnull; cur = cur->mNext)
++pCount;
PRUint32 length;
char* buffer = (char*) malloc(100 + MAXPATHLEN * pCount);
NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
char *end = buffer;
end += sprintf(end,
"[General]\n"
"StartWithLastProfile=%s\n\n",
mStartWithLast ? "1" : "0");
nsCAutoString path;
cur = mFirst;
pCount = 0;
while (cur) {
// if the profile dir is relative to appdir...
PRBool isRelative;
rv = mAppData->Contains(cur->mFile, PR_TRUE, &isRelative);
if (NS_SUCCEEDED(rv) && isRelative) {
// we use a relative descriptor
rv = cur->mFile->GetRelativeDescriptor(mAppData, path);
} else {
// otherwise, a persistent descriptor
rv = cur->mFile->GetPersistentDescriptor(path);
NS_ENSURE_SUCCESS(rv, rv);
}
end += sprintf(end,
"[Profile%u]\n"
"Name=%s\n"
"IsRelative=%s\n"
"Path=%s\n",
pCount, cur->mName.get(),
isRelative ? "1" : "0", path.get());
if (mChosen == cur) {
end += sprintf(end, "Default=1\n");
}
end += sprintf(end, "\n");
cur = cur->mNext;
++pCount;
}
FILE* writeFile;
rv = mListFile->OpenANSIFileDesc("w", &writeFile);
NS_ENSURE_SUCCESS(rv, rv);
if (buffer) {
length = end - buffer;
if (fwrite(buffer, sizeof(char), length, writeFile) != length) {
fclose(writeFile);
return NS_ERROR_UNEXPECTED;
}
}
fclose(writeFile);
return NS_OK;
}
NS_IMETHODIMP
nsToolkitProfileService::CreateInstance(nsISupports* aOuter, const nsID& aIID,
void** aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
// return this object
return QueryInterface(aIID, aResult);
}
NS_IMETHODIMP
nsToolkitProfileService::LockFactory(PRBool aVal)
{
return NS_OK;
}
nsresult
NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult)
{
nsToolkitProfileService* aThis = new nsToolkitProfileService();
nsresult rv = aThis->Init();
if (NS_FAILED(rv)) {
NS_ERROR("nsToolkitProfileService::Init failed!");
delete aThis;
return rv;
}
NS_ADDREF(*aResult = aThis);
return NS_OK;
}
nsresult
NS_GetFileFromPath(const char *aPath, nsILocalFile* *aResult)
{
#if defined(XP_MACOSX)
PRInt32 pathLen = strlen(aPath);
if (pathLen > MAXPATHLEN)
return NS_ERROR_INVALID_ARG;
CFURLRef fullPath =
CFURLCreateFromFileSystemRepresentation(NULL, aPath, pathLen, true);
if (!fullPath)
return NS_ERROR_FAILURE;
nsCOMPtr<nsILocalFile> lf;
nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE,
getter_AddRefs(lf));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsILocalFileMac> lfMac = do_QueryInterface(lf, &rv);
if (NS_SUCCEEDED(rv)) {
rv = lfMac->InitWithCFURL(fullPath);
if (NS_SUCCEEDED(rv))
NS_ADDREF(*aResult = lf);
}
}
CFRelease(fullPath);
return rv;
#elif defined(XP_UNIX) || defined(XP_OS2)
char fullPath[MAXPATHLEN];
if (!realpath(aPath, fullPath))
return NS_ERROR_FAILURE;
return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
aResult);
#elif defined(XP_WIN)
char fullPath[MAXPATHLEN];
if (!_fullpath(fullPath, aPath, MAXPATHLEN))
return NS_ERROR_FAILURE;
return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
aResult);
#elif defined(XP_BEOS)
BPath fullPath;
if (fullPath.SetTo(aPath, NULL, true))
return NS_ERROR_FAILURE;
return NS_NewNativeLocalFile(nsDependentCString(fullPath.Leaf()), PR_TRUE,
aResult);
#else
#error Platform-specific logic needed here.
#endif
}