2003-06-18 04:04:36 +04:00
|
|
|
/*-*- 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 Mozilla Roaming code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
2003-03-09 22:05:41 +03:00
|
|
|
* Ben Bucksch <http://www.bucksch.org> of
|
|
|
|
* Beonex <http://www.beonex.com>
|
2003-06-18 04:04:36 +04:00
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2002-2003
|
|
|
|
* 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 ***** */
|
2003-03-09 22:05:41 +03:00
|
|
|
|
|
|
|
/* The backend needs the settings in the Mozilla app registry
|
|
|
|
(via nsIRegistry), not in the prefs system (nsIPref;
|
|
|
|
it is not yet running when needed). This file implements
|
|
|
|
the saving of the settings (from the dialog) to the registry and reading
|
|
|
|
it back.
|
|
|
|
|
|
|
|
Oh Shit. When the user switches panes, the dialog loses all state. Nothing
|
|
|
|
restores it. But we can't save it to the registry either, the user might
|
|
|
|
cancel later. So, we have to store all values in our own, internal data
|
|
|
|
structure and later save it to the registry, if the user clicked OK.
|
|
|
|
|
|
|
|
To unify matters, I share a data structure between top.xul and files.js.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var gData; // for structure, see RegistryToData()
|
|
|
|
/* While each prefs pane (top and files) has its own |gData| var,
|
|
|
|
they all point to the same object, gotten from data manager.
|
|
|
|
I.e. top.js and files.js practically share the same
|
|
|
|
object. This is important so that files selection can be
|
|
|
|
disabled, if roaming is disabled, and be enabled as soon
|
|
|
|
as the user enabled roaming (but didn't save yet). */
|
|
|
|
|
|
|
|
|
|
|
|
// for pane switches
|
|
|
|
function Unload()
|
|
|
|
{
|
|
|
|
UIToData();
|
2003-03-22 18:30:48 +03:00
|
|
|
//parent.roaming.verifyData();
|
2003-03-09 22:05:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* *sigh*!!! when the user clicks OK in another pane,
|
|
|
|
all the other functions and even the consts are gone,
|
|
|
|
so creating an object. */
|
|
|
|
|
|
|
|
function RoamingPrefs()
|
|
|
|
{
|
|
|
|
// init
|
|
|
|
this.loaded = false; // already read from registry
|
|
|
|
this.changed = false; // any of the values changed, so save all
|
|
|
|
// user data
|
|
|
|
this.Enabled = false;
|
|
|
|
this.Method = 0; // int, reall enum: 0=stream, 1=copy
|
|
|
|
this.Files = new Array(); // of strings, will get another default below
|
|
|
|
this.Stream = new Object();
|
|
|
|
this.Stream.BaseURL = "";
|
|
|
|
this.Stream.Username = "";
|
|
|
|
this.Stream.SavePW = false;
|
|
|
|
this.Stream.Password = "";
|
|
|
|
this.Copy = new Object();
|
|
|
|
this.Copy.RemoteDir = "";
|
|
|
|
// caching(have to add that here or it will disappear during pane switches)
|
|
|
|
this.regkeyProf = undefined;
|
|
|
|
this.registry = undefined;
|
|
|
|
|
|
|
|
this.registryToData();
|
|
|
|
|
|
|
|
var me = this;
|
|
|
|
parent.hPrefWindow.registerOKCallbackFunc(function() { me.okClicked(); });
|
|
|
|
}
|
|
|
|
RoamingPrefs.prototype =
|
|
|
|
{
|
|
|
|
//from mozSRoaming*.cpp
|
|
|
|
kRegTreeProfile : "Profiles",
|
|
|
|
kRegTreeRoaming : "Roaming",
|
|
|
|
kRegKeyEnabled : "Enabled",
|
|
|
|
kRegKeyMethod : "Method",
|
|
|
|
kRegKeyFiles : "Files",
|
|
|
|
kRegValMethodStream : "stream",
|
|
|
|
kRegValMethodCopy : "copy",
|
|
|
|
kRegTreeStream : "Stream",
|
|
|
|
kRegKeyStreamURL : "BaseURL",
|
|
|
|
kRegKeyStreamUsername : "Username",
|
|
|
|
kRegKeyStreamPassword : "Password",
|
|
|
|
kRegKeyStreamSavePW : "SavePassword",
|
|
|
|
kRegTreeCopy : "Copy",
|
|
|
|
kRegKeyCopyDir : "RemoteDir",
|
|
|
|
// Registry layout:
|
|
|
|
// (root) (tree)
|
|
|
|
// + Profile (tree)
|
|
|
|
// + (current profile) (tree)
|
|
|
|
// + Roaming (tree)
|
|
|
|
// + Enabled (int)
|
|
|
|
// + Method (string, really enum: stream or copy)
|
|
|
|
// + Files (string, comma-separated list)
|
|
|
|
// + Stream (tree)
|
|
|
|
// | + BaseURL (string)
|
|
|
|
// | + Username (string)
|
|
|
|
// | + SavePW (int, really bool)
|
2003-06-16 02:52:10 +04:00
|
|
|
// | + Password (string, encrypted?)
|
2003-03-09 22:05:41 +03:00
|
|
|
// + Copy (tree)
|
|
|
|
// + RemoteDir (string)
|
|
|
|
|
|
|
|
okClicked : function()
|
|
|
|
{
|
|
|
|
if ("UIToData" in window) // unless a different pane is selected
|
|
|
|
{
|
|
|
|
UIToData();
|
|
|
|
}
|
2003-03-22 18:30:48 +03:00
|
|
|
this.verifyData();
|
2003-03-09 22:05:41 +03:00
|
|
|
this.dataToRegistry();
|
|
|
|
},
|
|
|
|
|
|
|
|
// Registry
|
|
|
|
|
|
|
|
// Read from the Mozilla registry into the internal data structure
|
|
|
|
registryToData : function()
|
|
|
|
{
|
|
|
|
if (this.loaded == true)
|
|
|
|
// prevent overwriting of user changes after pane switch back/forth
|
|
|
|
return;
|
|
|
|
|
|
|
|
// set default values, matching the hardcoded ones, in case we fail below
|
|
|
|
// internal logic
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
/* Default files
|
|
|
|
In case roaming was never set up, we will fail below at reg reading
|
|
|
|
and use the defaults in this. Set the default files list to some
|
|
|
|
sensible values, which we will get from the default prefs. */
|
|
|
|
var pref = Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService()
|
|
|
|
.QueryInterface(Components.interfaces.nsIPrefService)
|
|
|
|
.getDefaultBranch(null);
|
|
|
|
var value = pref.getCharPref("roaming.default.files");
|
|
|
|
this.Files = value.split(",");
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
/* to understand the structure of the registry,
|
|
|
|
see comment at the const defs above */
|
|
|
|
// get the Roaming reg branch
|
|
|
|
registry = Components.classes["@mozilla.org/registry;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIRegistry);
|
|
|
|
registry.openWellKnownRegistry(registry.ApplicationRegistry);
|
|
|
|
this.registry = registry;
|
|
|
|
var profMan = Components.classes["@mozilla.org/profile/manager;1"]
|
2003-06-18 21:02:10 +04:00
|
|
|
.getService(Components.interfaces.nsIProfile);
|
2003-03-09 22:05:41 +03:00
|
|
|
var regkey = registry.getKey(registry.Common, this.kRegTreeProfile);
|
|
|
|
regkey = registry.getKey(regkey, profMan.currentProfile);
|
|
|
|
this.regkeyProf = regkey;
|
|
|
|
regkey = registry.getKey(regkey, this.kRegTreeRoaming);
|
|
|
|
|
|
|
|
// enabled
|
|
|
|
value = registry.getInt(regkey, this.kRegKeyEnabled);
|
|
|
|
this.Enabled = value == 1 ? true : false;
|
|
|
|
|
|
|
|
// method (in the sense of the roaming implementation) selection
|
|
|
|
value = registry.getString(regkey, this.kRegKeyMethod);
|
|
|
|
if (value == this.kRegValMethodStream)
|
|
|
|
this.Method = 0;
|
|
|
|
else if (value == this.kRegValMethodCopy)
|
|
|
|
this.Method = 1;
|
|
|
|
|
|
|
|
// files
|
|
|
|
value = registry.getString(regkey, this.kRegKeyFiles);
|
|
|
|
this.Files = value.split(",");
|
|
|
|
// remove empty entries
|
|
|
|
for (var i = 0, l = this.Files.length; i < l; i++)
|
|
|
|
{
|
|
|
|
if (this.Files[i] == "")
|
|
|
|
this.Files.splice(i, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// stream
|
|
|
|
var regkeyRoaming = regkey; // save for use in "copy"
|
|
|
|
regkey = registry.getKey(regkeyRoaming, this.kRegTreeStream);
|
|
|
|
this.Stream.BaseURL = registry.getString(regkey, this.kRegKeyStreamURL);
|
|
|
|
this.Stream.Username = registry.getString(regkey,
|
|
|
|
this.kRegKeyStreamUsername);
|
|
|
|
this.Stream.Password = registry.getString(regkey,
|
|
|
|
this.kRegKeyStreamPassword);
|
|
|
|
value = registry.getInt(regkey, this.kRegKeyStreamSavePW);
|
|
|
|
this.Stream.SavePW = value == 1 ? true : false;
|
|
|
|
|
|
|
|
// copy
|
|
|
|
regkey = registry.getKey(regkeyRoaming, this.kRegTreeCopy);
|
|
|
|
this.Copy.RemoteDir = registry.getString(regkey, this.kRegKeyCopyDir);
|
|
|
|
|
|
|
|
// Note that read and write all values. We want to remember them,
|
|
|
|
// even if not used at the moment.
|
|
|
|
}
|
|
|
|
catch (e)
|
|
|
|
{
|
|
|
|
if (!this.regkeyProf)
|
|
|
|
this.showError("ErrorRegRead", undefined, e.message);
|
|
|
|
// later errors are expected, if we never wrote roaming prefs before,
|
|
|
|
// fatal otherwise, but we don't know the difference.
|
|
|
|
else
|
|
|
|
dump("Error, might be expected (roaming not set up yet): " + e + "\n");
|
|
|
|
}
|
|
|
|
this.loaded = true;
|
|
|
|
/* we might have failed above, but in this case, there is probably no
|
|
|
|
sense trying it again, so treat that the same as loaded.
|
|
|
|
This is important for the first setup - the first read will fail. */
|
|
|
|
},
|
|
|
|
|
|
|
|
// Saves from the internal data structure into the Mozilla registry
|
|
|
|
dataToRegistry : function()
|
|
|
|
{
|
|
|
|
if (!this.changed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var registry = this.registry;
|
|
|
|
if (!registry || !this.regkeyProf)
|
|
|
|
// arg, we had a fatal error during read, so bail out
|
|
|
|
return;
|
|
|
|
try {
|
|
|
|
var regkey = this.saveRegBranch(this.regkeyProf, this.kRegTreeRoaming);
|
|
|
|
|
|
|
|
// enabled
|
|
|
|
registry.setInt(regkey, this.kRegKeyEnabled,
|
|
|
|
this.Enabled == true ? 1 : 0);
|
|
|
|
|
|
|
|
// method (in the sense of the roaming implementation) selection
|
|
|
|
var value;
|
|
|
|
if (this.Method == 0)
|
|
|
|
value = this.kRegValMethodStream;
|
|
|
|
else if (this.Method == 1)
|
|
|
|
value = this.kRegValMethodCopy;
|
|
|
|
else // huh??
|
|
|
|
value = this.kRegValMethodStream;
|
|
|
|
registry.setString(regkey, this.kRegKeyMethod, value);
|
|
|
|
|
|
|
|
// files
|
|
|
|
value = "";
|
|
|
|
for (var i = 0, l = this.Files.length; i < l; i++)
|
|
|
|
{
|
|
|
|
var file = this.Files[i];
|
|
|
|
if (file && file != "")
|
|
|
|
value += file + ",";
|
|
|
|
}
|
|
|
|
// remove last ","
|
|
|
|
if (value.length > 0)
|
|
|
|
value = value.substring(0, value.length - 1);
|
|
|
|
registry.setString(regkey, this.kRegKeyFiles, value);
|
|
|
|
|
|
|
|
// stream
|
|
|
|
var regkeyRoaming = regkey; // save for use in "copy"
|
|
|
|
regkey = this.saveRegBranch(regkeyRoaming, this.kRegTreeStream);
|
|
|
|
registry.setString(regkey, this.kRegKeyStreamURL, this.Stream.BaseURL);
|
|
|
|
registry.setString(regkey, this.kRegKeyStreamUsername,
|
|
|
|
this.Stream.Username);
|
|
|
|
registry.setString(regkey, this.kRegKeyStreamPassword,
|
|
|
|
this.Stream.SavePW == true ? this.Stream.Password : "");
|
|
|
|
registry.setInt(regkey, this.kRegKeyStreamSavePW,
|
|
|
|
this.Stream.SavePW == true ? 1 : 0);
|
|
|
|
|
|
|
|
// copy
|
|
|
|
regkey = this.saveRegBranch(regkeyRoaming, this.kRegTreeCopy);
|
|
|
|
registry.setString(regkey, this.kRegKeyCopyDir, this.Copy.RemoteDir);
|
|
|
|
|
|
|
|
this.changed = false;
|
|
|
|
} catch (e) {
|
|
|
|
this.showError("ErrorRegWrite", undefined, e.message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// gets or creates registry branch, i.e. drop-in replacement for
|
|
|
|
// getKey/addKey returns either the regkey for branch or nothing, if failed
|
|
|
|
saveRegBranch : function(baseregkey, branchname)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
return this.registry.getKey(baseregkey, branchname);
|
|
|
|
} catch (e) { // XXX catch selectively
|
2003-06-18 20:51:29 +04:00
|
|
|
dumpError("got (expected?) exception " + e + "\n");
|
2003-03-09 22:05:41 +03:00
|
|
|
return this.registry.addKey(baseregkey, branchname);
|
|
|
|
// if that fails with an exception, throw it to caller
|
|
|
|
}
|
|
|
|
// throw unexpected errors to caller
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// Logic
|
|
|
|
|
|
|
|
// if some (user-entered) value is bad, shows error dialog and returns false
|
|
|
|
verifyData : function()
|
|
|
|
{
|
|
|
|
if (!this.Enabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var errorProp; // see showError();
|
|
|
|
var errorVal; // dito
|
|
|
|
var errorException;
|
|
|
|
if (this.Files.length <= 0)
|
|
|
|
{
|
|
|
|
errorProp = "NoFilesSelected";
|
|
|
|
}
|
|
|
|
if (this.Method == 0) // stream
|
|
|
|
{
|
|
|
|
// username
|
|
|
|
if (!this.Stream.Username || this.Stream.Username == "")
|
|
|
|
{
|
|
|
|
errorProp = "NoUsername";
|
|
|
|
}
|
|
|
|
|
|
|
|
// password
|
|
|
|
/* password may be empty despite savepw, we'll then ask for the password
|
|
|
|
during the next transfer and store it (by default) then. */
|
|
|
|
|
|
|
|
// base url
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var ioserv = Components.classes["@mozilla.org/network/io-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIIOService);
|
|
|
|
var baseURL = ioserv.newURI(this.Stream.BaseURL, null, null);
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
errorProp = "BaseURLMalformed";
|
|
|
|
errorVal = this.Stream.BaseURL;
|
|
|
|
//errorException = e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (this.Method == 1) // copy
|
|
|
|
{
|
|
|
|
// remote dir
|
|
|
|
if (this.Copy.RemoteDir == "")
|
|
|
|
{
|
|
|
|
errorProp = "RemoteDirNonExistant";
|
|
|
|
errorVal = " ";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var lf = Components.classes["@mozilla.org/file/local;1"]
|
|
|
|
.createInstance(Components.interfaces.nsILocalFile);
|
|
|
|
lf.initWithPath(this.Copy.RemoteDir);
|
|
|
|
if (!lf.exists())
|
|
|
|
{
|
|
|
|
throw "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
errorProp = "RemoteDirNonExistant";
|
|
|
|
errorVal = this.Copy.RemoteDir;
|
|
|
|
errorException = e.message; // will be undefined, if !lf.exist()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errorProp)
|
|
|
|
this.showError(errorProp, errorVal, errorException);
|
|
|
|
|
|
|
|
return errorProp ? true : false;
|
|
|
|
// XXX We should prevent closure and force the user to enter valid data,
|
|
|
|
// but I don't know how to do it.
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Warning: Don't try to show this after pref window disappeared, because
|
|
|
|
* we then can't display decendant windows (this error dialog) anymore.
|
|
|
|
*
|
|
|
|
* @param prop string stringbungle string name
|
|
|
|
* @param val string text to be replaced in string
|
|
|
|
* @param tech string internal error message (exception etc.). In English.
|
|
|
|
*/
|
|
|
|
showError : function(prop, val, tech)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
|
|
|
.getService()
|
|
|
|
.QueryInterface(Components.interfaces.nsIStringBundleService)
|
|
|
|
.createBundle("chrome://sroaming/locale/prefs.properties");
|
|
|
|
var dialogTitle = bundle.GetStringFromName("RoamingErrorTitle");
|
|
|
|
var text = dialogTitle + "\n";
|
|
|
|
if (val)
|
|
|
|
text += bundle.formatStringFromName(prop, [val], 1);
|
|
|
|
else
|
|
|
|
text += bundle.GetStringFromName(prop);
|
|
|
|
if (tech) // should we show exceptions to user?
|
|
|
|
text += "\n" + tech;
|
2003-06-18 19:56:32 +04:00
|
|
|
GetPromptService().alert(window, dialogTitle, text);
|
2003-03-09 22:05:41 +03:00
|
|
|
} catch(e) {
|
2003-06-18 20:18:48 +04:00
|
|
|
dumpError("Error while trying to display an error: " + e
|
|
|
|
+ " (original error: " + prop + " " + tech + ")\n");
|
2003-03-09 22:05:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// UI
|
|
|
|
|
|
|
|
function SwitchDeck(page, deckElement)
|
|
|
|
{
|
|
|
|
deckElement.setAttribute("selectedIndex", page);
|
|
|
|
}
|
|
|
|
|
|
|
|
function EnableElement(enabled, triggerElement, elementID)
|
|
|
|
{
|
|
|
|
var element = document.getElementById(elementID);
|
|
|
|
if(!enabled)
|
|
|
|
element.setAttribute("disabled", "true");
|
|
|
|
else
|
|
|
|
element.removeAttribute("disabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
function EnableTree(enabled, element)
|
|
|
|
{
|
|
|
|
if (!element || !element.setAttribute)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(!enabled)
|
|
|
|
element.setAttribute("disabled", "true");
|
|
|
|
else
|
|
|
|
element.removeAttribute("disabled");
|
|
|
|
|
|
|
|
// EnableTree direct children (recursive)
|
|
|
|
var children = element.childNodes;
|
|
|
|
for (var i = 0; i < children.length; i++)
|
|
|
|
EnableTree(enabled, children.item(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
function InitElement(elementID)
|
|
|
|
{
|
|
|
|
var e = document.getElementById(elementID);
|
|
|
|
eval(e.getAttribute("oncommand").replace(/this/g, "e")); //hackish, but WFM
|
|
|
|
}
|
|
|
|
|
|
|
|
function E(elementID)
|
|
|
|
{
|
|
|
|
return document.getElementById(elementID);
|
|
|
|
}
|