2 // Various helpful utility functions.
4 // ### Import Mozilla Services
5 const { Services
} = ChromeUtils
.import("resource://gre/modules/Services.jsm");
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
)) {
17 return prefs
.getBoolPref(prefName
);
19 return prefs
.getIntPref(prefName
);
20 case prefs
.PREF_STRING
:
21 return prefs
.getCharPref(prefName
);
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) {
33 prefHandler(getPrefValue(prefName
));
36 observe(subject
, topic
, data
) {
37 if (data
=== prefName
) {
42 prefs
.addObserver(prefName
, observer
);
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);
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
) {
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
79 // Provides access to process environment variables.
80 let env
= Cc
["@mozilla.org/process/environment;1"].getService(
85 // Reads the environment variable of the given name.
86 var getEnv = function(name
) {
87 return env
.exists(name
) ? env
.get(name
) : undefined;
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.
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
;
121 // ## Tor control protocol utility functions
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().
134 var len
= aStr
.length
;
135 if (len
< 2 || '"' != aStr
.charAt(0) || '"' != aStr
.charAt(len
- 1)) {
139 const kHexRE
= /[0-9A-Fa-f]{2}/;
140 const kOctalRE
= /[0-7]{3}/;
143 var lastCharIndex
= len
- 2;
144 while (i
<= lastCharIndex
) {
145 var c
= aStr
.charAt(i
);
147 if (++i
> lastCharIndex
) {
148 throw new Error("missing character after \\");
154 } else if ("r" == c
) {
156 } else if ("t" == c
) {
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
);
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
);
189 } else if ('"' == c
) {
190 throw new Error('unescaped " within string');
197 // Convert from UTF-8 to Unicode. TODO: is UTF-8 always used in protocol?
198 return decodeURIComponent(escape(rv
));
201 // Within Tor Launcher, the file components/tl-protocol.js also contains a
202 // copy of _isDigit().
205 return aChar
&& kRE
.test(aChar
);
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
=> {
218 return Services
.eTLD
.getBaseDomainFromHost(hostname
);
221 e
.result
== Cr
.NS_ERROR_HOST_IS_IP_ADDRESS
||
222 e
.result
== Cr
.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
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
;
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
;
251 var m_tb_torlog
= Cc
["@torproject.org/torbutton-logger;1"].getService(
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
);
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..
270 // load localization strings
271 function torbutton_get_stringbundle() {
272 var o_stringbundle
= false;
275 var oBundle
= Services
.strings
;
276 o_stringbundle
= oBundle
.createBundle(
277 "chrome://torbutton/locale/torbutton.properties"
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
) {
291 if (!m_tb_string_bundle
) {
292 m_tb_string_bundle
= torbutton_get_stringbundle();
295 return m_tb_string_bundle
.GetStringFromName(propertyname
);
297 torbutton_log(4, "Unlocalized string " + propertyname
);
303 // Export utility functions for external use.
304 let EXPORTED_SYMBOLS
= [
309 "getDomainForBrowser",
313 "show_torbrowser_manual",
317 "torbutton_get_property_string",