File: internalFunctions.js

package info (click to toggle)
downthemall 2.0.13-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 4,284 kB
  • sloc: xml: 927; makefile: 8
file content (439 lines) | stat: -rw-r--r-- 11,890 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
/* You may find the license in the LICENSE file */

/* dTa-only code! - DO NOT include in overlays or such! */

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const ctor = Components.Constructor;
const module = Cu.import;
const Exception = Components.Exception;

const FileFactory = new ctor('@mozilla.org/file/local;1', 'nsILocalFile', 'initWithPath');
const SoundFactory = new ctor('@mozilla.org/sound;1', 'nsISound', 'play');
const CryptoHash = new ctor("@mozilla.org/security/hash;1", "nsICryptoHash");
	
// shared state defines

module("resource://dta/constants.jsm", this);

const DTA = {
	showPreferences: function(pane) DTA.Mediator.showPreferences(window, pane)
};
module("resource://dta/api.jsm", DTA);

function openUrl(url, ref) DTA.Mediator.openUrl(window, url, ref);

const Debug = DTA.Debug;
const Preferences = DTA.Preferences;

module("resource://dta/support/icons.jsm");

/**
 * Get DOM Element(s) by Id. Missing ids are silently ignored!
 * 
 * @param ids
 *          One of more Ids
 * @return Either the element when there was just one parameter, or an array of
 *         elements.
 */
function $() {
	if (arguments.length == 1) {
		return document.getElementById(arguments[0]);
	}
	let elements = [];
	for (let i = 0, e = arguments.length; i < e; ++i) {
		let element = document.getElementById(arguments[i]);
		if (element) {
			elements.push(element);
		}
		else {
			Debug.log("requested a non-existing element: " + arguments[i]);
		}
	}
	return elements;
}

var Utils = {
	/**
	 * Opens up a directory picker and returns the user selected path.
	 * 
	 * @param predefined
	 *          The starting path to display when dialog opens up
	 * @text text The description text to be displayed
	 * @return A string containing the user selected path, or false if user
	 *         cancels the dialog.
	 */
	FilePicker: Components.Constructor('@mozilla.org/filepicker;1', 'nsIFilePicker', 'init'),
	askForDir: function (predefined, text) {
		try {
			// nsIFilePicker object
			predefined = predefined ? predefined.trim() : '';
			let nsIFilePicker = Ci.nsIFilePicker;
			let fp = new Utils.FilePicker(window, text, nsIFilePicker.modeGetFolder);
			fp.appendFilters(nsIFilePicker.filterAll);
		
			// locate current directory
			let dest = this.validateDir(predefined);
			if (dest) {
				fp.displayDirectory = dest;
			}
		
			// open file picker
			let res = fp.show();
	
			if (res == nsIFilePicker.returnOK) {
				return fp.file.path.addFinalSlash();
			}
		}
		catch (ex) {
			Debug.log("Utils.askForDir():", ex);
		}
		return false;
	},
	/**
	 * Performs all the needed controls to see if the specified path is valid, is
	 * creable and writable and his drive has some free disk space.
	 * 
	 * @param path
	 *          The path to test
	 * @return a nsILocalFile to the specified path if it's valid, false if it
	 *         wasn't
	 */
	validateDir: function(path) {
		let directory = null;
		try {
			if (!(path instanceof Ci.nsILocalFile)) {
				if (!path || !String(path).trim().length) {
					return false;
				}
				directory = new FileFactory(path);
			}
			else {
				directory = path.clone();
			}
		}
		catch (ex) {
			Debug.log("Invalid path supplied", ex);
		}
		if (!directory) {
			return false;
		}
		try {
			// look for the first directory that exists.
			let parent = directory.clone();
			while (parent && !parent.exists()) {
				parent = parent.parent;
			}
			if (parent) {
				// from nsIFile
				parent = parent.QueryInterface(Ci.nsILocalFile);
				// we look for a directory that is writable and has some disk-space
				if (parent.isDirectory() && parent.isReadable() && parent.isWritable()) {
					//try {
					//	return parent.diskSpaceAvailable ? directory : false;
					//}
					//catch (ex) {
						// Solaris compat: #889
						return directory;
					//}
				}
			}
		}
		catch(ex) {
			Debug.log('Checking permissions threw', ex);
		}
		return false;
	},
	/**
	 * Gets the disk-space available for a nsILocalFile. Here, because
	 * diskSpaceAvailable requires valid path and/or path to be a directory
	 * 
	 * @param file
	 *          Valid nsILocalFile
	 * @return the disk-space available to the caller
	 * @author Nils
	 */
	getFreeDisk: function(file) {
		while (file) {
			if (file.exists() && file.isDirectory()) {
				//try {
				//	return file.diskSpaceAvailable;
				//}
				//catch (ex) {
					// Solaris compat: #889
					// As we cannot get a correct value simply return max int64_t
					return 9223372036854775807;
				//}				
			}
			file = file.parent;
		}
		return 0;
	},
	/**
	 * Play a sound file (if prefs allow to do so)
	 * 
	 * @param name
	 *          Name of the sound (corresponding to the pref name and the file
	 *          name of desired sound)
	 */
	playSound: function(name) {
		
		try {
			var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
				.getService(Ci.nsIXULRuntime);
			if (/linux|sun|bsd|aix|hp|dragonfly|irix/i.test(xulRuntime.OS) && /64/.test(xulRuntime.XPCOMABI)) {
				throw new Components.Exception("*nix 64 - freeze problems");
			}
			
			if (Preferences.getExt("sounds." + name, false)) {
				new SoundFactory(("chrome://dta/skin/sounds/" + name + ".wav").toURI());
			}
		}
		catch(ex) {
			Debug.log("Playing " + name + " sound failed", ex);
		}
	},

	formatKBytes: function U_formatKBytes(aNumber, decimalPlace) {
		aNumber = Number(aNumber) / 1024;
		
		if (!isFinite(aNumber)) {
			return 'NaN';
		}
		return _('sizeKB', [aNumber.toFixed(arguments.length > 1 ? decimalPlace : 1)]);
	},

	formatConflictName: function U_formatConflictName(basename, conflicts) {
		if (!conflicts) {
			return basename;
		}
		let ext = '', pos = basename.lastIndexOf('.');
		if (pos != -1) {
			ext = basename.slice(pos);
			basename = basename.slice(0, pos);
		}
		return basename + '_' + Utils.formatNumber(conflicts) + ext;
	}
};

(function() {
	function createFormatter(units, scale) {
		const sunits = units;
		const nunits = sunits.length;
		const s = scale;
		return function(val, decimalPlace) {
			val = Number(val);
			if (!isFinite(val)) {
				return 'NaN';
			}
			let unit = sunits[0];
			for (let i = 1; val > s && i < nunits; ++i) {
				val /= 1024;
				unit = sunits[i];
			}
			decimalPlace = arguments.length > 1 ? decimalPlace : unit[1];
			return _(unit[0], [val.toFixed(decimalPlace)]);			
		}
	}
	Utils.formatBytes = createFormatter([['sizeB', 0], ['sizeKB', 1], ['sizeMB', 2], ['sizeGB', 2], ['sizeTB', 3]], 875);
	Utils.formatSpeed = createFormatter([['sizeBs', 0], ['sizeKBs', 1], ['sizeMBs', 2], ['sizeGBs', 3]], 1023);
})();

Components.utils.import('resource://dta/utils.jsm', Utils);
const SYSTEMSLASH = Utils.SYSTEMSLASH;


//XXX Copy from utils.jsm
//XXX Cannot use directly; yields NS_ERROR_INVALID_VALUE then
/**
 * Installs a new lazy getter
 * @param aObject (object) Object to install the getter to
 * @param aName (string) Name of the getter property
 * @param aLambda (function) Initializer function (called once, return value becomes getter value)
 */
function setNewGetter(aObject, aName, aLambda) {
	if (aName in aObject) {
		throw new Exception(aName + " is already defined in context " + aObject);
	}
	try {
		aObject.__defineGetter__(aName, function() {
			delete aObject[aName];
			return aObject[aName] = aLambda.apply(aObject);
		});

	}
	catch (ex) {
		Debug.log(aName);
		Debug.log(ex);
	}
}

/**
 * Install lazy service getter
 * @param context (object) Object to install the getter to
 * @param name Name of the getter property
 * @param contract (string) Contract id of the service
 * @param iface (string) Interface of the service
 */
function ServiceGetter(context, name, contract, iface) {
	if (!iface) {
		iface = Ci.nsISupports;
	}
	else if (typeof iface == "string") {
		iface = Ci[iface];
	}
	setNewGetter(
		context,
		name,
		function() {
			try {
				return Cc[contract].getService(iface);
			}
			catch (ex) {
				Debug.log(ex);
				Debug.log(contract);
				Debug.log(iface);
				throw ex;
			}
		}
	);	
}

/**
 * Installs lazy instance getter.
 * The instance will be created only once and then reused
 * @param context (object) Object to install the getter to
 * @param name Name of the getter property
 * @param contract (string) Contract id of the class
 * @param iface (string) Interface of the class
 * @param initFuncName (string) Optional. Name of the function to call on the object instance once created.
 * @param ... (mixed) Optional. Any arguments to initFunc
 */
function InstanceGetter(context, name, contract, iface, initFuncName/*, args */) {
	if (!iface) {
		iface = Ci.nsISupports;
	}
	else if (typeof iface == "string") {
		iface = Ci[iface];
	}

	// build an arguments array for the initFunc, stripping the first 5 arguments
	let args = Array.filter(arguments, function(e, i) i > 4);
	setNewGetter(
		context,
		name,
		function() {
			let rv = Cc[contract].createInstance(iface);
			if (initFuncName) {
				rv[initFuncName].apply(rv, args);
			}
			return rv;
		}
	);
}

/**
 * returns a new UUID in string representation
 * @return String UUID
 */
setNewGetter(this, "newUUIDString", function() {
	let uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
	return function() {
		return uuidgen.generateUUID().toString();
	};
});

ServiceGetter(this, "IOService", "@mozilla.org/network/io-service;1", "nsIIOService2");

Utils.extendString(String);

/**
 * Get a (formatted) locale property string.
 * 
 * @param stringId
 *          Id of desired string corresponding to the .properties file(s)
 * @param ...
 *          Optional. Format parameters
 * @return String for given Name
 * @throws Exception
 *           if stringID is not found or before the dialog was initialized
 * @author Nils
 */
setNewGetter(this, "_", function() {
	let bundles = new Utils.StringBundles(document);
	return function() {
		if (arguments.length == 1) {
			return bundles.getString(arguments[0]);
		}
		return bundles.getFormattedString.apply(bundles, arguments);
	} 
});

InstanceGetter(this, "converter", "@mozilla.org/intl/scriptableunicodeconverter", "nsIScriptableUnicodeConverter");

/**
 * Convert a value into a hash
 * 
 * @param data
 *          Data to hash. Either an nsInputStream or String-castable.
 * @param algorithm
 *          Optional. Either a number or a string referring to an nsICryptoHash
 *          function. (default: sha1)
 * @param encoding
 *          Optional. One of: HASH_HEX (0), HASH_BIN(1), HASH_B64 (2) (default:
 *          HASH_HEX)
 * @param datalen
 *          Optional, only for streams. Length of data to hash (default: hash
 *          whole stream)
 * @return A string representing the hash a in given encoding.
 * @author Nils
 */
const HASH_HEX = 0x0;
const HASH_BIN = 0x1;
const HASH_B64 = 0x2;
function hash(value, algorithm, encoding, datalen) {
	var ch = new CryptoHash();
	if (!algorithm) {
		algorithm = ch.SHA1;
	}
	if (!encoding) {
		encoding = HASH_HEX;
	}
	if (typeof(algorithm) == 'string' || algorithm instanceof String) {
		ch.initWithString(algorithm);
	} 
	else {
		ch.init(algorithm);
	}
	if (value instanceof Ci.nsIInputStream) {
		datalen = Number(datalen);
		ch.updateFromStream(value, datalen > 0 ? datalen : 0xffffffff);
	}
	else {
		converter.charset = 'utf8';		
		value = converter.convertToByteArray(Utils.atos(value), {});
		ch.update(value, value.length);
	}
	var rv = ch.finish(encoding == HASH_B64);
	if (encoding == HASH_HEX) {
		rv = Utils.hexdigest(rv);
	}
	return rv;
}

(function() {
	let _ic = {};
	module("resource://dta/support/iconcheat.jsm", _ic);
	_ic.loadWindow(window);
})();

__defineGetter__("DefaultDownloadsDirectory", function() {
	let dlm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
	try {
		return dlm.userDownloadsDirectory;	
	}
	catch (ex) {}
	return dlm.defaultDownloadsDirectory;
});