Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
4 const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
6 let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
8 /**
9 * Push required permissions and test if |navigator.mozMobileMessage| exists.
10 * Resolve if it does, reject otherwise.
11 *
12 * Fulfill params:
13 * manager -- an reference to navigator.mozMobileMessage.
14 *
15 * Reject params: (none)
16 *
17 * @return A deferred promise.
18 */
19 let manager;
20 function ensureMobileMessage() {
21 let deferred = Promise.defer();
23 let permissions = [{
24 "type": "sms",
25 "allow": 1,
26 "context": document,
27 }];
28 SpecialPowers.pushPermissions(permissions, function() {
29 ok(true, "permissions pushed: " + JSON.stringify(permissions));
31 manager = window.navigator.mozMobileMessage;
32 if (manager) {
33 log("navigator.mozMobileMessage is instance of " + manager.constructor);
34 } else {
35 log("navigator.mozMobileMessage is undefined.");
36 }
38 if (manager instanceof MozMobileMessageManager) {
39 deferred.resolve(manager);
40 } else {
41 deferred.reject();
42 }
43 });
45 return deferred.promise;
46 }
48 /**
49 * Wait for one named MobileMessageManager event.
50 *
51 * Resolve if that named event occurs. Never reject.
52 *
53 * Fulfill params: the DOMEvent passed.
54 *
55 * @param aEventName
56 * A string event name.
57 *
58 * @return A deferred promise.
59 */
60 function waitForManagerEvent(aEventName) {
61 let deferred = Promise.defer();
63 manager.addEventListener(aEventName, function onevent(aEvent) {
64 manager.removeEventListener(aEventName, onevent);
66 ok(true, "MobileMessageManager event '" + aEventName + "' got.");
67 deferred.resolve(aEvent);
68 });
70 return deferred.promise;
71 }
73 /**
74 * Send a SMS message to a single receiver. Resolve if it succeeds, reject
75 * otherwise.
76 *
77 * Fulfill params:
78 * message -- the sent SmsMessage.
79 *
80 * Reject params:
81 * error -- a DOMError.
82 *
83 * @param aReceiver the address of the receiver.
84 * @param aText the text body of the message.
85 *
86 * @return A deferred promise.
87 */
88 function sendSmsWithSuccess(aReceiver, aText) {
89 let deferred = Promise.defer();
91 let request = manager.send(aReceiver, aText);
92 request.onsuccess = function(event) {
93 deferred.resolve(event.target.result);
94 };
95 request.onerror = function(event) {
96 deferred.reject(event.target.error);
97 };
99 return deferred.promise;
100 }
102 /**
103 * Send a MMS message with specified parameters. Resolve if it fails, reject
104 * otherwise.
105 *
106 * Fulfill params:
107 * {
108 * message, -- the failed MmsMessage
109 * error, -- error of the send request
110 * }
111 *
112 * Reject params: (none)
113 *
114 * @param aMmsParameters a MmsParameters instance.
115 *
116 * @param aSendParameters a MmsSendParameters instance.
117 *
118 * @return A deferred promise.
119 */
120 function sendMmsWithFailure(aMmsParameters, aSendParameters) {
121 let deferred = Promise.defer();
123 let result = { message: null, error: null };
124 function got(which, value) {
125 result[which] = value;
126 if (result.message != null && result.error != null) {
127 deferred.resolve(result);
128 }
129 }
131 manager.addEventListener("failed", function onfailed(event) {
132 manager.removeEventListener("failed", onfailed);
133 got("message", event.message);
134 });
136 let request = manager.sendMMS(aMmsParameters, aSendParameters);
137 request.onsuccess = function(event) {
138 deferred.reject();
139 };
140 request.onerror = function(event) {
141 got("error", event.target.error);
142 }
144 return deferred.promise;
145 }
147 /**
148 * Retrieve messages from database.
149 *
150 * Fulfill params:
151 * messages -- an array of {Sms,Mms}Message instances.
152 *
153 * Reject params:
154 * event -- a DOMEvent
155 *
156 * @param aFilter an optional MozSmsFilter instance.
157 * @param aReverse a boolean value indicating whether the order of the messages
158 * should be reversed.
159 *
160 * @return A deferred promise.
161 */
162 function getMessages(aFilter, aReverse) {
163 let deferred = Promise.defer();
165 if (!aFilter) {
166 aFilter = new MozSmsFilter;
167 }
168 let messages = [];
169 let cursor = manager.getMessages(aFilter, aReverse || false);
170 cursor.onsuccess = function(aEvent) {
171 if (cursor.result) {
172 messages.push(cursor.result);
173 cursor.continue();
174 return;
175 }
177 deferred.resolve(messages);
178 };
179 cursor.onerror = deferred.reject.bind(deferred);
181 return deferred.promise;
182 }
184 /**
185 * Retrieve all messages from database.
186 *
187 * Fulfill params:
188 * messages -- an array of {Sms,Mms}Message instances.
189 *
190 * Reject params:
191 * event -- a DOMEvent
192 *
193 * @return A deferred promise.
194 */
195 function getAllMessages() {
196 return getMessages(null, false);
197 }
199 /**
200 * Retrieve all threads from database.
201 *
202 * Fulfill params:
203 * threads -- an array of MozMobileMessageThread instances.
204 *
205 * Reject params:
206 * event -- a DOMEvent
207 *
208 * @return A deferred promise.
209 */
210 function getAllThreads() {
211 let deferred = Promise.defer();
213 let threads = [];
214 let cursor = manager.getThreads();
215 cursor.onsuccess = function(aEvent) {
216 if (cursor.result) {
217 threads.push(cursor.result);
218 cursor.continue();
219 return;
220 }
222 deferred.resolve(threads);
223 };
224 cursor.onerror = deferred.reject.bind(deferred);
226 return deferred.promise;
227 }
229 /**
230 * Retrieve a single specified thread from database.
231 *
232 * Fulfill params:
233 * thread -- a MozMobileMessageThread instance.
234 *
235 * Reject params:
236 * event -- a DOMEvent if an error occurs in the retrieving process, or
237 * undefined if there's no such thread.
238 *
239 * @aThreadId a numeric value identifying the target thread.
240 *
241 * @return A deferred promise.
242 */
243 function getThreadById(aThreadId) {
244 return getAllThreads()
245 .then(function(aThreads) {
246 for (let thread of aThreads) {
247 if (thread.id === aThreadId) {
248 return thread;
249 }
250 }
251 throw undefined;
252 });
253 }
255 /**
256 * Delete messages specified from database.
257 *
258 * Fulfill params:
259 * result -- an array of boolean values indicating whether delesion was
260 * actually performed on the message record with corresponding id.
261 *
262 * Reject params:
263 * event -- a DOMEvent.
264 *
265 * @aMessageId an array of numeric values identifying the target messages.
266 *
267 * @return An empty array if nothing to be deleted; otherwise, a deferred promise.
268 */
269 function deleteMessagesById(aMessageIds) {
270 if (!aMessageIds.length) {
271 ok(true, "no message to be deleted");
272 return [];
273 }
275 let deferred = Promise.defer();
277 let request = manager.delete(aMessageIds);
278 request.onsuccess = function(event) {
279 deferred.resolve(event.target.result);
280 };
281 request.onerror = deferred.reject.bind(deferred);
283 return deferred.promise;
284 }
286 /**
287 * Delete messages specified from database.
288 *
289 * Fulfill params:
290 * result -- an array of boolean values indicating whether delesion was
291 * actually performed on the message record with corresponding id.
292 *
293 * Reject params:
294 * event -- a DOMEvent.
295 *
296 * @aMessages an array of {Sms,Mms}Message instances.
297 *
298 * @return A deferred promise.
299 */
300 function deleteMessages(aMessages) {
301 let ids = messagesToIds(aMessages);
302 return deleteMessagesById(ids);
303 }
305 /**
306 * Delete all messages from database.
307 *
308 * Fulfill params:
309 * ids -- an array of numeric values identifying those deleted
310 * {Sms,Mms}Messages.
311 *
312 * Reject params:
313 * event -- a DOMEvent.
314 *
315 * @return A deferred promise.
316 */
317 function deleteAllMessages() {
318 return getAllMessages().then(deleteMessages);
319 }
321 let pendingEmulatorCmdCount = 0;
323 /**
324 * Send emulator command with safe guard.
325 *
326 * We should only call |finish()| after all emulator command transactions
327 * end, so here comes with the pending counter. Resolve when the emulator
328 * gives positive response, and reject otherwise.
329 *
330 * Fulfill params:
331 * result -- an array of emulator response lines.
332 *
333 * Reject params:
334 * result -- an array of emulator response lines.
335 *
336 * @return A deferred promise.
337 */
338 function runEmulatorCmdSafe(aCommand) {
339 let deferred = Promise.defer();
341 ++pendingEmulatorCmdCount;
342 runEmulatorCmd(aCommand, function(aResult) {
343 --pendingEmulatorCmdCount;
345 ok(true, "Emulator response: " + JSON.stringify(aResult));
346 if (Array.isArray(aResult) && aResult[0] === "OK") {
347 deferred.resolve(aResult);
348 } else {
349 deferred.reject(aResult);
350 }
351 });
353 return deferred.promise;
354 }
356 /**
357 * Send simple text SMS to emulator.
358 *
359 * Fulfill params:
360 * result -- an array of emulator response lines.
361 *
362 * Reject params:
363 * result -- an array of emulator response lines.
364 *
365 * @return A deferred promise.
366 */
367 function sendTextSmsToEmulator(aFrom, aText) {
368 let command = "sms send " + aFrom + " " + aText;
369 return runEmulatorCmdSafe(command);
370 }
372 /**
373 * Send raw SMS TPDU to emulator.
374 *
375 * @param: aPdu
376 * A hex string representing the whole SMS T-PDU.
377 *
378 * Fulfill params:
379 * result -- an array of emulator response lines.
380 *
381 * Reject params:
382 * result -- an array of emulator response lines.
383 *
384 * @return A deferred promise.
385 */
386 function sendRawSmsToEmulator(aPdu) {
387 let command = "sms pdu " + aPdu;
388 return runEmulatorCmdSafe(command);
389 }
391 /**
392 * Send multiple raw SMS TPDU to emulator and wait
393 *
394 * @param: aPdus
395 * A array of hex strings. Each represents a SMS T-PDU.
396 *
397 * Fulfill params:
398 * result -- array of resolved Promise, where
399 * result[0].message representing the received message.
400 * result[1-n] represents the response of sent emulator command.
401 *
402 * Reject params:
403 * result -- an array of emulator response lines.
404 *
405 * @return A deferred promise.
406 */
407 function sendMultipleRawSmsToEmulatorAndWait(aPdus) {
408 let promises = [];
410 promises.push(waitForManagerEvent("received"));
411 for (let pdu of aPdus) {
412 promises.push(sendRawSmsToEmulator(pdu));
413 }
415 return Promise.all(promises);
416 }
418 /**
419 * Create a new array of id attribute of input messages.
420 *
421 * @param aMessages an array of {Sms,Mms}Message instances.
422 *
423 * @return an array of numeric values.
424 */
425 function messagesToIds(aMessages) {
426 let ids = [];
427 for (let message of aMessages) {
428 ids.push(message.id);
429 }
430 return ids;
431 }
433 /**
434 * Flush permission settings and call |finish()|.
435 */
436 function cleanUp() {
437 waitFor(function() {
438 SpecialPowers.flushPermissions(function() {
439 // Use ok here so that we have at least one test run.
440 ok(true, "permissions flushed");
442 finish();
443 });
444 }, function() {
445 return pendingEmulatorCmdCount === 0;
446 });
447 }
449 /**
450 * Basic test routine helper for mobile message tests.
451 *
452 * This helper does nothing but clean-ups.
453 *
454 * @param aTestCaseMain
455 * A function that takes no parameter.
456 */
457 function startTestBase(aTestCaseMain) {
458 Promise.resolve()
459 .then(aTestCaseMain)
460 .then(cleanUp, function() {
461 ok(false, 'promise rejects during test.');
462 cleanUp();
463 });
464 }
466 /**
467 * Common test routine helper for mobile message tests.
468 *
469 * This function ensures global |manager| variable is available during the
470 * process and performs clean-ups as well.
471 *
472 * @param aTestCaseMain
473 * A function that takes no parameter.
474 */
475 function startTestCommon(aTestCaseMain) {
476 startTestBase(function() {
477 return ensureMobileMessage()
478 .then(deleteAllMessages)
479 .then(aTestCaseMain)
480 .then(deleteAllMessages);
481 });
482 }
484 /**
485 * Helper to run the test case only needed in Multi-SIM environment.
486 *
487 * @param aTest
488 * A function which will be invoked w/o parameter.
489 * @return a Promise object.
490 */
491 function runIfMultiSIM(aTest) {
492 let numRIL;
493 try {
494 numRIL = SpecialPowers.getIntPref("ril.numRadioInterfaces");
495 } catch (ex) {
496 numRIL = 1; // Pref not set.
497 }
499 if (numRIL > 1) {
500 return aTest();
501 } else {
502 log("Not a Multi-SIM environment. Test is skipped.");
503 return Promise.resolve();
504 }
505 }