Translation updates
[torbutton.git] / modules / utils.js
blob30947a737cb95c71862c537945e4f9093de316f6
1 // # Utils.js
2 // Various helpful utility functions.
4 // ### Import Mozilla Services
5 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
7 // ## Pref utils
9 // __prefs__. A shortcut to Mozilla Services.prefs.
10 let prefs = Services.prefs;
12 // __getPrefValue(prefName)__
13 // Returns the current value of a preference, regardless of its type.
14 var getPrefValue = function(prefName) {
15 switch (prefs.getPrefType(prefName)) {
16 case prefs.PREF_BOOL:
17 return prefs.getBoolPref(prefName);
18 case prefs.PREF_INT:
19 return prefs.getIntPref(prefName);
20 case prefs.PREF_STRING:
21 return prefs.getCharPref(prefName);
22 default:
23 return null;
27 // __bindPref(prefName, prefHandler, init)__
28 // Applies prefHandler whenever the value of the pref changes.
29 // If init is true, applies prefHandler to the current value.
30 // Returns a zero-arg function that unbinds the pref.
31 var bindPref = function(prefName, prefHandler, init = false) {
32 let update = () => {
33 prefHandler(getPrefValue(prefName));
35 observer = {
36 observe(subject, topic, data) {
37 if (data === prefName) {
38 update();
42 prefs.addObserver(prefName, observer);
43 if (init) {
44 update();
46 return () => {
47 prefs.removeObserver(prefName, observer);
51 // __bindPrefAndInit(prefName, prefHandler)__
52 // Applies prefHandler to the current value of pref specified by prefName.
53 // Re-applies prefHandler whenever the value of the pref changes.
54 // Returns a zero-arg function that unbinds the pref.
55 var bindPrefAndInit = (prefName, prefHandler) =>
56 bindPref(prefName, prefHandler, true);
58 // ## Observers
60 // __observe(topic, callback)__.
61 // Observe the given topic. When notification of that topic
62 // occurs, calls callback(subject, data). Returns a zero-arg
63 // function that stops observing.
64 var observe = function(topic, callback) {
65 let observer = {
66 observe(aSubject, aTopic, aData) {
67 if (topic === aTopic) {
68 callback(aSubject, aData);
72 Services.obs.addObserver(observer, topic);
73 return () => Services.obs.removeObserver(observer, topic);
76 // ## Environment variables
78 // __env__.
79 // Provides access to process environment variables.
80 let env = Cc["@mozilla.org/process/environment;1"].getService(
81 Ci.nsIEnvironment
84 // __getEnv(name)__.
85 // Reads the environment variable of the given name.
86 var getEnv = function(name) {
87 return env.exists(name) ? env.get(name) : undefined;
90 // __getLocale
91 // Returns the app locale to be used in tor-related urls.
92 var getLocale = function() {
93 const locale = Services.locale.appLocaleAsBCP47;
94 if (locale === "ja-JP-macos") {
95 // We don't want to distinguish the mac locale.
96 return "ja";
98 return locale;
101 // ## Windows
103 // __dialogsByName__.
104 // Map of window names to dialogs.
105 let dialogsByName = {};
107 // __showDialog(parent, url, name, features, arg1, arg2, ...)__.
108 // Like window.openDialog, but if the window is already
109 // open, just focuses it instead of opening a new one.
110 var showDialog = function(parent, url, name, features) {
111 let existingDialog = dialogsByName[name];
112 if (existingDialog && !existingDialog.closed) {
113 existingDialog.focus();
114 return existingDialog;
116 let newDialog = parent.openDialog.apply(parent, Array.slice(arguments, 1));
117 dialogsByName[name] = newDialog;
118 return newDialog;
121 // ## Tor control protocol utility functions
123 let _torControl = {
124 // Unescape Tor Control string aStr (removing surrounding "" and \ escapes).
125 // Based on Vidalia's src/common/stringutil.cpp:string_unescape().
126 // Returns the unescaped string. Throws upon failure.
127 // Within Tor Launcher, the file components/tl-protocol.js also contains a
128 // copy of _strUnescape().
129 _strUnescape(aStr) {
130 if (!aStr) {
131 return aStr;
134 var len = aStr.length;
135 if (len < 2 || '"' != aStr.charAt(0) || '"' != aStr.charAt(len - 1)) {
136 return aStr;
139 const kHexRE = /[0-9A-Fa-f]{2}/;
140 const kOctalRE = /[0-7]{3}/;
141 var rv = "";
142 var i = 1;
143 var lastCharIndex = len - 2;
144 while (i <= lastCharIndex) {
145 var c = aStr.charAt(i);
146 if ("\\" == c) {
147 if (++i > lastCharIndex) {
148 throw new Error("missing character after \\");
151 c = aStr.charAt(i);
152 if ("n" == c) {
153 rv += "\n";
154 } else if ("r" == c) {
155 rv += "\r";
156 } else if ("t" == c) {
157 rv += "\t";
158 } else if ("x" == c) {
159 if (i + 2 > lastCharIndex) {
160 throw new Error("not enough hex characters");
163 let s = aStr.substr(i + 1, 2);
164 if (!kHexRE.test(s)) {
165 throw new Error("invalid hex characters");
168 let val = parseInt(s, 16);
169 rv += String.fromCharCode(val);
170 i += 3;
171 } else if (this._isDigit(c)) {
172 let s = aStr.substr(i, 3);
173 if (i + 2 > lastCharIndex) {
174 throw new Error("not enough octal characters");
177 if (!kOctalRE.test(s)) {
178 throw new Error("invalid octal characters");
181 let val = parseInt(s, 8);
182 rv += String.fromCharCode(val);
183 i += 3;
184 } // "\\" and others
185 else {
186 rv += c;
187 ++i;
189 } else if ('"' == c) {
190 throw new Error('unescaped " within string');
191 } else {
192 rv += c;
193 ++i;
197 // Convert from UTF-8 to Unicode. TODO: is UTF-8 always used in protocol?
198 return decodeURIComponent(escape(rv));
199 }, // _strUnescape()
201 // Within Tor Launcher, the file components/tl-protocol.js also contains a
202 // copy of _isDigit().
203 _isDigit(aChar) {
204 const kRE = /^\d$/;
205 return aChar && kRE.test(aChar);
207 }; // _torControl
209 // __unescapeTorString(str, resultObj)__.
210 // Unescape Tor Control string str (removing surrounding "" and \ escapes).
211 // Returns the unescaped string. Throws upon failure.
212 var unescapeTorString = function(str) {
213 return _torControl._strUnescape(str);
216 var getFPDFromHost = hostname => {
217 try {
218 return Services.eTLD.getBaseDomainFromHost(hostname);
219 } catch (e) {
220 if (
221 e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
222 e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
224 return hostname;
227 return null;
230 // Assuming this is called with gBrowser.selectedBrowser
231 var getDomainForBrowser = browser => {
232 let fpd = browser.contentPrincipal.originAttributes.firstPartyDomain;
233 // Bug 31562: For neterror or certerror, get the original URL from
234 // browser.currentURI and use it to calculate the firstPartyDomain.
235 let knownErrors = ["about:neterror", "about:certerror"];
236 let documentURI = browser.documentURI;
237 if (
238 documentURI &&
239 documentURI.schemeIs("about") &&
240 knownErrors.some(x => documentURI.spec.startsWith(x))
242 let knownSchemes = ["http", "https", "ftp"];
243 let currentURI = browser.currentURI;
244 if (currentURI && knownSchemes.some(x => currentURI.schemeIs(x))) {
245 fpd = getFPDFromHost(currentURI.host) || fpd;
248 return fpd;
251 var m_tb_torlog = Cc["@torproject.org/torbutton-logger;1"].getService(
252 Ci.nsISupports
253 ).wrappedJSObject;
255 var m_tb_string_bundle = torbutton_get_stringbundle();
257 function torbutton_safelog(nLevel, sMsg, scrub) {
258 m_tb_torlog.safe_log(nLevel, sMsg, scrub);
259 return true;
262 function torbutton_log(nLevel, sMsg) {
263 m_tb_torlog.log(nLevel, sMsg);
265 // So we can use it in boolean expressions to determine where the
266 // short-circuit is..
267 return true;
270 // load localization strings
271 function torbutton_get_stringbundle() {
272 var o_stringbundle = false;
274 try {
275 var oBundle = Services.strings;
276 o_stringbundle = oBundle.createBundle(
277 "chrome://torbutton/locale/torbutton.properties"
279 } catch (err) {
280 o_stringbundle = false;
282 if (!o_stringbundle) {
283 torbutton_log(5, "ERROR (init): failed to find torbutton-bundle");
286 return o_stringbundle;
289 function torbutton_get_property_string(propertyname) {
290 try {
291 if (!m_tb_string_bundle) {
292 m_tb_string_bundle = torbutton_get_stringbundle();
295 return m_tb_string_bundle.GetStringFromName(propertyname);
296 } catch (e) {
297 torbutton_log(4, "Unlocalized string " + propertyname);
300 return propertyname;
303 // Export utility functions for external use.
304 let EXPORTED_SYMBOLS = [
305 "bindPref",
306 "bindPrefAndInit",
307 "getEnv",
308 "getLocale",
309 "getDomainForBrowser",
310 "getPrefValue",
311 "observe",
312 "showDialog",
313 "show_torbrowser_manual",
314 "unescapeTorString",
315 "torbutton_safelog",
316 "torbutton_log",
317 "torbutton_get_property_string",