/* * 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 Session Roaming code. * * The Initial Developer of the Original Code is * Ben Bucksch of * Beonex * Portions created by Ben Bucksch are Copyright (C) 2002 Ben Bucksch. * All Rights Reserved. * * Contributor(s): */ /* 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(); //parent.roaming.verifyData(); } /* *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) // | + Password (string, encrypted) // + Copy (tree) // + RemoteDir (string) okClicked : function() { if ("UIToData" in window) // unless a different pane is selected { UIToData(); } this.verifyData(); 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"] .getService(Components.interfaces.nsIProfile); 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 dump("got (expected?) exception " + e + "\n"); 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 promptService = Components .classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService); 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; promptService.alert(window, dialogTitle, text); } catch(e) { dump("Error while trying to display an error: " + e + " (original error: " + prop + " " + tech + ")\n"); } } } // 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); }