mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Merge from mozilla-central
This commit is contained in:
commit
9b15a69d3e
@ -2,9 +2,9 @@
|
||||
#export GONK_PRODUCT=generic
|
||||
#gonk="/home/cjones/mozilla/gonk-toolchain-$GONK_TOOLCHAIN_VERSION"
|
||||
|
||||
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-prof-gonk
|
||||
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS="-s -j16"
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j8"
|
||||
|
||||
ac_add_options --enable-application=b2g
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1331241604000">
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1331848989000">
|
||||
<emItems>
|
||||
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
@ -65,8 +65,8 @@
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i72" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
|
||||
<versionRange minVersion="0" maxVersion="3.4.1.194" severity="1">
|
||||
<emItem blockID="i72" os="WINNT" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
|
||||
<versionRange minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
|
||||
@ -153,6 +153,10 @@
|
||||
<versionRange minVersion="2.0" maxVersion="2.0">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i73" id="a1g0a9g219d@a1.com">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i51" id="admin@youtubeplayer.com">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
</versionRange>
|
||||
|
@ -229,6 +229,9 @@ body[narrow] #launcher[session] {
|
||||
padding: 14px 6px;
|
||||
min-width: 88px;
|
||||
max-width: 176px;
|
||||
max-height: 85px;
|
||||
vertical-align: top;
|
||||
white-space: normal;
|
||||
background: transparent padding-box;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2.5px;
|
||||
@ -241,9 +244,6 @@ body[narrow] #launcher[session] {
|
||||
|
||||
body[narrow] #launcher[session] > .launchButton {
|
||||
margin: 4px 1px;
|
||||
max-height: 85px;
|
||||
vertical-align: top;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.launchButton:hover {
|
||||
|
@ -110,6 +110,15 @@ let gBrowserThumbnails = {
|
||||
|
||||
let channel = aBrowser.docShell.currentDocumentChannel;
|
||||
|
||||
// No valid document channel. We shouldn't take a screenshot.
|
||||
if (!channel)
|
||||
return false;
|
||||
|
||||
// Don't take screenshots of internally redirecting about: pages.
|
||||
// This includes error pages.
|
||||
if (channel.originalURI.schemeIs("about"))
|
||||
return false;
|
||||
|
||||
try {
|
||||
// If the channel is a nsIHttpChannel get its http status code.
|
||||
let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
@ -94,7 +94,11 @@ let gDrop = {
|
||||
// A new link was dragged onto the grid. Create it by pinning its URL.
|
||||
let dt = aEvent.dataTransfer;
|
||||
let [url, title] = dt.getData("text/x-moz-url").split(/[\r\n]+/);
|
||||
gPinnedLinks.pin({url: url, title: title}, index);
|
||||
let link = {url: url, title: title};
|
||||
gPinnedLinks.pin(link, index);
|
||||
|
||||
// Make sure the newly added link is not blocked.
|
||||
gBlockedLinks.unblock(link);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -92,6 +92,7 @@ nsContextMenu.prototype = {
|
||||
} catch (e) { }
|
||||
this.isTextSelected = this.isTextSelection();
|
||||
this.isContentSelected = this.isContentSelection();
|
||||
this.onPlainTextLink = false;
|
||||
|
||||
// Initialize (disable/remove) menu items.
|
||||
this.initItems();
|
||||
@ -132,7 +133,6 @@ nsContextMenu.prototype = {
|
||||
|
||||
// Time to do some bad things and see if we've highlighted a URL that
|
||||
// isn't actually linked.
|
||||
var onPlainTextLink = false;
|
||||
if (this.isTextSelected && !this.onLink) {
|
||||
// Ok, we have some text, let's figure out if it looks like a URL.
|
||||
let selection = document.commandDispatcher.focusedWindow
|
||||
@ -190,14 +190,14 @@ nsContextMenu.prototype = {
|
||||
if (uri && uri.host) {
|
||||
this.linkURI = uri;
|
||||
this.linkURL = this.linkURI.spec;
|
||||
onPlainTextLink = true;
|
||||
this.onPlainTextLink = true;
|
||||
}
|
||||
}
|
||||
|
||||
var shouldShow = this.onSaveableLink || isMailtoInternal || onPlainTextLink;
|
||||
var shouldShow = this.onSaveableLink || isMailtoInternal || this.onPlainTextLink;
|
||||
this.showItem("context-openlink", shouldShow);
|
||||
this.showItem("context-openlinkintab", shouldShow);
|
||||
this.showItem("context-openlinkincurrent", onPlainTextLink);
|
||||
this.showItem("context-openlinkincurrent", this.onPlainTextLink);
|
||||
this.showItem("context-sep-open", shouldShow);
|
||||
},
|
||||
|
||||
@ -222,9 +222,9 @@ nsContextMenu.prototype = {
|
||||
this.showItem("context-savepage", shouldShow);
|
||||
this.showItem("context-sendpage", shouldShow);
|
||||
|
||||
// Save+Send link depends on whether we're in a link.
|
||||
this.showItem("context-savelink", this.onSaveableLink);
|
||||
this.showItem("context-sendlink", this.onSaveableLink);
|
||||
// Save+Send link depends on whether we're in a link, or selected text matches valid URL pattern.
|
||||
this.showItem("context-savelink", this.onSaveableLink || this.onPlainTextLink);
|
||||
this.showItem("context-sendlink", this.onSaveableLink || this.onPlainTextLink);
|
||||
|
||||
// Save image depends on having loaded its content, video and audio don't.
|
||||
this.showItem("context-saveimage", this.onLoadedImage || this.onCanvas);
|
||||
@ -310,7 +310,7 @@ nsContextMenu.prototype = {
|
||||
this.showItem("context-bookmarkpage",
|
||||
!(this.isContentSelected || this.onTextInput || this.onLink ||
|
||||
this.onImage || this.onVideo || this.onAudio));
|
||||
this.showItem("context-bookmarklink", this.onLink && !this.onMailtoLink);
|
||||
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink) || this.onPlainTextLink);
|
||||
this.showItem("context-searchselect", isTextSelected);
|
||||
this.showItem("context-keywordfield",
|
||||
this.onTextInput && this.onKeywordField);
|
||||
@ -1073,9 +1073,15 @@ nsContextMenu.prototype = {
|
||||
// Save URL of clicked-on link.
|
||||
saveLink: function() {
|
||||
var doc = this.target.ownerDocument;
|
||||
var linkText;
|
||||
// If selected text is found to match valid URL pattern.
|
||||
if (this.onPlainTextLink)
|
||||
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
|
||||
else
|
||||
linkText = this.linkText();
|
||||
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
|
||||
|
||||
this.saveHelper(this.linkURL, this.linkText(), null, true, doc);
|
||||
this.saveHelper(this.linkURL, linkText, null, true, doc);
|
||||
},
|
||||
|
||||
sendLink: function() {
|
||||
@ -1390,8 +1396,14 @@ nsContextMenu.prototype = {
|
||||
},
|
||||
|
||||
bookmarkLink: function CM_bookmarkLink() {
|
||||
var linkText;
|
||||
// If selected text is found to match valid URL pattern.
|
||||
if (this.onPlainTextLink)
|
||||
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
|
||||
else
|
||||
linkText = this.linkText();
|
||||
window.top.PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId, this.linkURL,
|
||||
this.linkText());
|
||||
linkText);
|
||||
},
|
||||
|
||||
addBookmarkForFrame: function CM_addBookmarkForFrame() {
|
||||
|
@ -25,6 +25,7 @@ _BROWSER_FILES = \
|
||||
browser_newtab_bug723121.js \
|
||||
browser_newtab_bug725996.js \
|
||||
browser_newtab_bug734043.js \
|
||||
browser_newtab_bug735987.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
|
22
browser/base/content/test/newtab/browser_newtab_bug735987.js
Normal file
22
browser/base/content/test/newtab/browser_newtab_bug735987.js
Normal file
@ -0,0 +1,22 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function runTests() {
|
||||
setLinks("0,1,2,3,4,5,6,7,8");
|
||||
setPinnedLinks("");
|
||||
|
||||
yield addNewTabPageTab();
|
||||
checkGrid("0,1,2,3,4,5,6,7,8");
|
||||
|
||||
yield simulateDrop(cells[1]);
|
||||
checkGrid("0,99p,1,2,3,4,5,6,7");
|
||||
|
||||
yield blockCell(cells[1]);
|
||||
checkGrid("0,1,2,3,4,5,6,7,8");
|
||||
|
||||
yield simulateDrop(cells[1]);
|
||||
checkGrid("0,99p,1,2,3,4,5,6,7");
|
||||
|
||||
yield blockCell(cells[1]);
|
||||
checkGrid("0,1,2,3,4,5,6,7,8");
|
||||
}
|
@ -58,6 +58,8 @@ Browser context menu subtest.
|
||||
<menuitem></menuitem>
|
||||
</menu>
|
||||
</div>
|
||||
<div id="test-select-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
|
||||
<div id="test-select-text-link">http://mozilla.com</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -20,6 +20,7 @@ Browser context menu tests.
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -72,6 +73,16 @@ function invokeItemAction(generatedItemId)
|
||||
ok(!pagemenu.hasAttribute("hopeless"), "attribute got removed");
|
||||
}
|
||||
|
||||
function selectText(element) {
|
||||
// Clear any previous selections before selecting new element.
|
||||
subwindow.getSelection().removeAllRanges();
|
||||
|
||||
var div = subwindow.document.createRange();
|
||||
div.setStartBefore(element);
|
||||
div.setEndAfter(element);
|
||||
subwindow.getSelection().addRange(div);
|
||||
}
|
||||
|
||||
function getVisibleMenuItems(aMenu, aData) {
|
||||
var items = [];
|
||||
var accessKeys = {};
|
||||
@ -667,6 +678,45 @@ function runTest(testNum) {
|
||||
"context-viewinfo", true
|
||||
].concat(inspectItems));
|
||||
closeContextMenu();
|
||||
selectText(selecttext); // Select text prior to opening context menu.
|
||||
openContextMenuFor(selecttext); // Invoke context menu for next test.
|
||||
return;
|
||||
|
||||
case 22:
|
||||
// Context menu for selected text
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
// This test is only enabled on Mac due to bug 736399.
|
||||
checkContextMenu(["context-copy", true,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"context-searchselect", true,
|
||||
"context-viewpartialsource-selection", true
|
||||
].concat(inspectItems));
|
||||
}
|
||||
closeContextMenu();
|
||||
selectText(selecttextlink); // Select text prior to opening context menu.
|
||||
openContextMenuFor(selecttextlink); // Invoke context menu for next test.
|
||||
return;
|
||||
|
||||
case 23:
|
||||
// Context menu for selected text which matches valid URL pattern
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
// This test is only enabled on Mac due to bug 736399.
|
||||
checkContextMenu(["context-openlinkincurrent", true,
|
||||
"context-openlinkintab", true,
|
||||
"context-openlink", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-savelink", true,
|
||||
"context-sendlink", true,
|
||||
"context-copy", true,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"context-searchselect", true,
|
||||
"context-viewpartialsource-selection", true
|
||||
].concat(inspectItems));
|
||||
}
|
||||
closeContextMenu();
|
||||
|
||||
subwindow.close();
|
||||
SimpleTest.finish();
|
||||
@ -674,7 +724,6 @@ function runTest(testNum) {
|
||||
|
||||
/*
|
||||
* Other things that would be nice to test:
|
||||
* - selected text
|
||||
* - spelling / misspelled word (in text input?)
|
||||
* - check state of disabled items
|
||||
* - test execution of menu items (maybe as a separate test?)
|
||||
@ -734,6 +783,8 @@ function startTest() {
|
||||
contenteditable.focus(); // content editable needs to be focused to enable spellcheck
|
||||
inputspell = subwindow.document.getElementById("test-input-spellcheck");
|
||||
pagemenu = subwindow.document.getElementById("test-pagemenu");
|
||||
selecttext = subwindow.document.getElementById("test-select-text");
|
||||
selecttextlink = subwindow.document.getElementById("test-select-text-link");
|
||||
|
||||
contextMenu.addEventListener("popupshown", function() { runTest(++testNum); }, false);
|
||||
runTest(1);
|
||||
|
@ -109,6 +109,7 @@ let PageThumbs = {
|
||||
* @param aCallback The function to be called when finished (optional).
|
||||
*/
|
||||
captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
|
||||
let url = aBrowser.currentURI.spec;
|
||||
this.capture(aBrowser.contentWindow, function (aInputStream) {
|
||||
let telemetryStoreTime = new Date();
|
||||
|
||||
@ -123,7 +124,7 @@ let PageThumbs = {
|
||||
}
|
||||
|
||||
// Get a writeable cache entry.
|
||||
PageThumbsCache.getWriteEntry(aBrowser.currentURI.spec, function (aEntry) {
|
||||
PageThumbsCache.getWriteEntry(url, function (aEntry) {
|
||||
if (!aEntry) {
|
||||
finish(false);
|
||||
return;
|
||||
|
@ -13,6 +13,7 @@ include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_FILES = \
|
||||
browser_thumbnails_capture.js \
|
||||
browser_thumbnails_bug726727.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* These tests ensure that capturing a sites's thumbnail, saving it and
|
||||
* retrieving it from the cache works.
|
||||
*/
|
||||
function runTests() {
|
||||
// Create a tab that shows an error page.
|
||||
let tab = gBrowser.addTab("http://non-existant.url/");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
yield browser.addEventListener("DOMContentLoaded", function onLoad() {
|
||||
browser.removeEventListener("DOMContentLoaded", onLoad, false);
|
||||
executeSoon(next);
|
||||
}, false);
|
||||
|
||||
ok(!gBrowserThumbnails._shouldCapture(browser), "we're not going to capture an error page");
|
||||
}
|
@ -383,6 +383,15 @@ let BlockedLinks = {
|
||||
Storage.set("blockedLinks", this.links);
|
||||
},
|
||||
|
||||
/**
|
||||
* Unblocks a given link.
|
||||
* @param aLink The link to unblock.
|
||||
*/
|
||||
unblock: function BlockedLinks_unblock(aLink) {
|
||||
if (this.isBlocked(aLink))
|
||||
delete this.links[aLink.url];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a given link is blocked.
|
||||
* @param aLink The link to check.
|
||||
|
@ -23,6 +23,11 @@ const FILTER_TIMESTAMP = "timestamp";
|
||||
const FILTER_NUMBERS = "numbers";
|
||||
const FILTER_DELIVERY = "delivery";
|
||||
|
||||
const READ_ONLY = "readonly";
|
||||
const READ_WRITE = "readwrite";
|
||||
const PREV = "prev";
|
||||
const NEXT = "next";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
|
||||
"@mozilla.org/sms/smsservice;1",
|
||||
"nsISmsService");
|
||||
@ -44,13 +49,13 @@ function SmsDatabaseService() {
|
||||
gIDBManager.initWindowless(GLOBAL_SCOPE);
|
||||
|
||||
let that = this;
|
||||
this.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function(error, txn, store){
|
||||
this.newTxn(READ_ONLY, function(error, txn, store){
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
// In order to get the highest key value, we open a key cursor in reverse
|
||||
// order and get only the first pointed value.
|
||||
let request = store.openCursor(null, Ci.nsIIDBCursor.PREV);
|
||||
let request = store.openCursor(null, PREV);
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
@ -165,7 +170,7 @@ SmsDatabaseService.prototype = {
|
||||
* Start a new transaction.
|
||||
*
|
||||
* @param txn_type
|
||||
* Type of transaction (e.g. IDBTransaction.READ_WRITE)
|
||||
* Type of transaction (e.g. READ_WRITE)
|
||||
* @param callback
|
||||
* Function to call when the transaction is available. It will
|
||||
* be invoked with the transaction and the 'sms' object store.
|
||||
@ -254,7 +259,7 @@ SmsDatabaseService.prototype = {
|
||||
onMessageListCreated: function onMessageListCreated(messageList, requestId) {
|
||||
if (DEBUG) debug("Message list created: " + messageList);
|
||||
let self = this;
|
||||
self.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function (error, txn, store) {
|
||||
self.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (error) {
|
||||
gSmsRequestManager.notifyReadMessageListFailed(
|
||||
requestId, Ci.nsISmsRequestManager.INTERNAL_ERROR);
|
||||
@ -295,7 +300,7 @@ SmsDatabaseService.prototype = {
|
||||
this.lastKey += 1;
|
||||
message.id = this.lastKey;
|
||||
if (DEBUG) debug("Going to store " + JSON.stringify(message));
|
||||
this.newTxn(Ci.nsIIDBTransaction.READ_WRITE, function(error, txn, store) {
|
||||
this.newTxn(READ_WRITE, function(error, txn, store) {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
@ -330,7 +335,7 @@ SmsDatabaseService.prototype = {
|
||||
|
||||
getMessage: function getMessage(messageId, requestId) {
|
||||
if (DEBUG) debug("Retrieving message with ID " + messageId);
|
||||
this.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function (error, txn, store) {
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (error) {
|
||||
if (DEBUG) debug(error);
|
||||
gSmsRequestManager.notifyGetSmsFailed(
|
||||
@ -382,46 +387,28 @@ SmsDatabaseService.prototype = {
|
||||
},
|
||||
|
||||
deleteMessage: function deleteMessage(messageId, requestId) {
|
||||
let deleted = false;
|
||||
let self = this;
|
||||
this.newTxn(Ci.nsIIDBTransaction.READ_WRITE, function (error, txn, store) {
|
||||
this.newTxn(READ_WRITE, function (error, txn, store) {
|
||||
if (error) {
|
||||
gSmsRequestManager.notifySmsDeleteFailed(
|
||||
requestId, Ci.nsISmsRequestManager.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
let request = store.delete(messageId);
|
||||
let request = store.count(messageId);
|
||||
|
||||
request.onerror = function onerror(event) {
|
||||
if (DEBUG) debug("Caught error on request ", event.target.errorCode);
|
||||
//TODO look at event.target.errorCode
|
||||
gSmsRequestManager.notifySmsDeleteFailed(
|
||||
requestId, Ci.nsISmsRequestManager.INTERNAL_ERROR);
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let count = event.target.result;
|
||||
if (DEBUG) debug("Count for messageId " + messageId + ": " + count);
|
||||
deleted = (count == 1);
|
||||
if (deleted) {
|
||||
store.delete(messageId);
|
||||
}
|
||||
};
|
||||
|
||||
txn.oncomplete = function oncomplete(event) {
|
||||
if (DEBUG) debug("Transaction " + txn + " completed.");
|
||||
// Once we transaction is done, we need to check if we actually deleted
|
||||
// the message. As IndexedDB does not provide the affected records info,
|
||||
// we need to try to get the message from the database again to check
|
||||
// that it is actually gone.
|
||||
self.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function (error, txn, store) {
|
||||
let request = store.getAll(messageId);
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let deleted = (event.target.result.length == 0);
|
||||
gSmsRequestManager.notifySmsDeleted(requestId, deleted);
|
||||
};
|
||||
request.onerror = function onerror(event) {
|
||||
if (DEBUG) {
|
||||
debug("Error checking the message deletion " +
|
||||
event.target.errorCode);
|
||||
}
|
||||
//TODO should we notify here as an internal error? The failed check
|
||||
// does not mean that the deletion has failed, so maybe we
|
||||
// should notify successfully.
|
||||
gSmsRequestManager.notifySmsDeleteFailed(
|
||||
requestId, Ci.nsISmsRequestManager.INTERNAL_ERROR);
|
||||
};
|
||||
});
|
||||
gSmsRequestManager.notifySmsDeleted(requestId, deleted);
|
||||
};
|
||||
|
||||
txn.onerror = function onerror(event) {
|
||||
@ -478,7 +465,7 @@ SmsDatabaseService.prototype = {
|
||||
};
|
||||
|
||||
let self = this;
|
||||
this.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function (error, txn, store) {
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (error) {
|
||||
errorCb(error);
|
||||
return;
|
||||
@ -495,7 +482,7 @@ SmsDatabaseService.prototype = {
|
||||
} else if (filter.endDate != null) {
|
||||
timeKeyRange = IDBKeyRange.upperBound(filter.endDate.getTime());
|
||||
}
|
||||
let direction = reverse ? Ci.nsIIDBCursor.PREV : Ci.nsIIDBCursor.NEXT;
|
||||
let direction = reverse ? PREV : NEXT;
|
||||
let timeRequest = store.index("timestamp").openKeyCursor(timeKeyRange,
|
||||
direction);
|
||||
|
||||
@ -573,7 +560,7 @@ SmsDatabaseService.prototype = {
|
||||
gSmsRequestManager.notifyNoMessageInList(requestId);
|
||||
return;
|
||||
}
|
||||
this.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function (error, txn, store) {
|
||||
this.newTxn(READ_ONLY, function (error, txn, store) {
|
||||
if (DEBUG) debug("Fetching message " + messageId);
|
||||
let request = store.get(messageId);
|
||||
let message;
|
||||
|
@ -408,13 +408,13 @@ RadioInterfaceLayer.prototype = {
|
||||
handleSmsReceived: function handleSmsReceived(message) {
|
||||
debug("handleSmsReceived: " + JSON.stringify(message));
|
||||
let id = gSmsDatabaseService.saveReceivedMessage(message.sender || null,
|
||||
message.body || null,
|
||||
message.fullBody || null,
|
||||
message.timestamp);
|
||||
let sms = gSmsService.createSmsMessage(id,
|
||||
DOM_SMS_DELIVERY_RECEIVED,
|
||||
message.sender || null,
|
||||
message.receiver || null,
|
||||
message.body || null,
|
||||
message.fullBody || null,
|
||||
message.timestamp);
|
||||
Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
|
||||
},
|
||||
@ -422,12 +422,14 @@ RadioInterfaceLayer.prototype = {
|
||||
handleSmsSent: function handleSmsSent(message) {
|
||||
debug("handleSmsSent: " + JSON.stringify(message));
|
||||
let timestamp = Date.now();
|
||||
let id = gSmsDatabaseService.saveSentMessage(message.number, message.body, timestamp);
|
||||
let id = gSmsDatabaseService.saveSentMessage(message.number,
|
||||
message.fullBody,
|
||||
timestamp);
|
||||
let sms = gSmsService.createSmsMessage(id,
|
||||
DOM_SMS_DELIVERY_SENT,
|
||||
null,
|
||||
message.number,
|
||||
message.body,
|
||||
message.fullBody,
|
||||
timestamp);
|
||||
//TODO handle errors (bug 727319)
|
||||
gSmsRequestManager.notifySmsSent(message.requestId, sms);
|
||||
@ -532,19 +534,387 @@ RadioInterfaceLayer.prototype = {
|
||||
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION, force);
|
||||
},
|
||||
|
||||
/**
|
||||
* List of tuples of national language identifier pairs.
|
||||
*
|
||||
* TODO: Support static/runtime settings, see bug 733331.
|
||||
*/
|
||||
enabledGsmTableTuples: [
|
||||
[RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT],
|
||||
],
|
||||
|
||||
/**
|
||||
* Use 16-bit reference number for concatenated outgoint messages.
|
||||
*
|
||||
* TODO: Support static/runtime settings, see bug 733331.
|
||||
*/
|
||||
segmentRef16Bit: false,
|
||||
|
||||
/**
|
||||
* Get valid SMS concatenation reference number.
|
||||
*/
|
||||
_segmentRef: 0,
|
||||
get nextSegmentRef() {
|
||||
let ref = this._segmentRef++;
|
||||
|
||||
this._segmentRef %= (this.segmentRef16Bit ? 65535 : 255);
|
||||
|
||||
// 0 is not a valid SMS concatenation reference number.
|
||||
return ref + 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate encoded length using specified locking/single shift table
|
||||
*
|
||||
* @param message
|
||||
* message string to be encoded.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
*
|
||||
* @return encoded length in septets.
|
||||
*
|
||||
* @note that the algorithm used in this function must match exactly with
|
||||
* GsmPDUHelper#writeStringAsSeptets.
|
||||
*/
|
||||
_countGsm7BitSeptets: function _countGsm7BitSeptets(message, langTable, langShiftTable) {
|
||||
let length = 0;
|
||||
for (let msgIndex = 0; msgIndex < message.length; msgIndex++) {
|
||||
let septet = langTable.indexOf(message.charAt(msgIndex));
|
||||
|
||||
// According to 3GPP TS 23.038, section 6.1.1 General notes, "The
|
||||
// characters marked '1)' are not used but are displayed as a space."
|
||||
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
length++;
|
||||
continue;
|
||||
}
|
||||
|
||||
septet = langShiftTable.indexOf(message.charAt(msgIndex));
|
||||
if (septet < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
||||
// character and therefore must not be used for language specific
|
||||
// characters."
|
||||
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The character is not found in locking shfit table, but could be
|
||||
// encoded as <escape><char> with single shift table. Note that it's
|
||||
// still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE,
|
||||
// but we can display it as a space in this case as said in previous
|
||||
// comment.
|
||||
length += 2;
|
||||
}
|
||||
|
||||
return length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length of specified message string encoded in GSM 7Bit
|
||||
* alphabets.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
*
|
||||
* @return null or an options object with attributes `dcs`,
|
||||
* `userDataHeaderLength`, `encodedFullBodyLength`, `langIndex`,
|
||||
* `langShiftIndex`, `segmentMaxSeq` set.
|
||||
*
|
||||
* @see #_calculateUserDataLength().
|
||||
*/
|
||||
_calculateUserDataLength7Bit: function _calculateUserDataLength7Bit(message) {
|
||||
let options = null;
|
||||
let minUserDataSeptets = Number.MAX_VALUE;
|
||||
for (let i = 0; i < this.enabledGsmTableTuples.length; i++) {
|
||||
let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i];
|
||||
|
||||
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
|
||||
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
|
||||
|
||||
let bodySeptets = this._countGsm7BitSeptets(message,
|
||||
langTable,
|
||||
langShiftTable);
|
||||
if (bodySeptets < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let headerLen = 0;
|
||||
if (langIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langIndex
|
||||
}
|
||||
if (langShiftIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langShiftIndex
|
||||
}
|
||||
|
||||
// Calculate full user data length, note the extra byte is for header len
|
||||
let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
|
||||
let userDataSeptets = bodySeptets + headerSeptets;
|
||||
let segments = bodySeptets ? 1 : 0;
|
||||
if (userDataSeptets > RIL.PDU_MAX_USER_DATA_7BIT) {
|
||||
if (this.segmentRef16Bit) {
|
||||
headerLen += 6;
|
||||
} else {
|
||||
headerLen += 5;
|
||||
}
|
||||
|
||||
headerSeptets = Math.ceil((headerLen + 1) * 8 / 7);
|
||||
let segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT - headerSeptets;
|
||||
segments = Math.ceil(bodySeptets / segmentSeptets);
|
||||
userDataSeptets = bodySeptets + headerSeptets * segments;
|
||||
}
|
||||
|
||||
if (userDataSeptets >= minUserDataSeptets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
minUserDataSeptets = userDataSeptets;
|
||||
|
||||
options = {
|
||||
dcs: RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET,
|
||||
encodedFullBodyLength: bodySeptets,
|
||||
userDataHeaderLength: headerLen,
|
||||
langIndex: langIndex,
|
||||
langShiftIndex: langShiftIndex,
|
||||
segmentMaxSeq: segments,
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length of specified message string encoded in UCS2.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
*
|
||||
* @return an options object with attributes `dcs`, `userDataHeaderLength`,
|
||||
* `encodedFullBodyLength`, `segmentMaxSeq` set.
|
||||
*
|
||||
* @see #_calculateUserDataLength().
|
||||
*/
|
||||
_calculateUserDataLengthUCS2: function _calculateUserDataLengthUCS2(message) {
|
||||
let bodyChars = message.length;
|
||||
let headerLen = 0;
|
||||
let headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2);
|
||||
let segments = bodyChars ? 1 : 0;
|
||||
if ((bodyChars + headerChars) > RIL.PDU_MAX_USER_DATA_UCS2) {
|
||||
if (this.segmentRef16Bit) {
|
||||
headerLen += 6;
|
||||
} else {
|
||||
headerLen += 5;
|
||||
}
|
||||
|
||||
headerChars = Math.ceil((headerLen + 1) / 2);
|
||||
let segmentChars = RIL.PDU_MAX_USER_DATA_UCS2 - headerChars;
|
||||
segments = Math.ceil(bodyChars / segmentChars);
|
||||
}
|
||||
|
||||
return {
|
||||
dcs: RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET,
|
||||
encodedFullBodyLength: bodyChars * 2,
|
||||
userDataHeaderLength: headerLen,
|
||||
segmentMaxSeq: segments,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length and its encoding.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
*
|
||||
* @return an options object with some or all of following attributes set:
|
||||
*
|
||||
* @param dcs
|
||||
* Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
|
||||
* constants.
|
||||
* @param fullBody
|
||||
* Original unfragmented text message.
|
||||
* @param userDataHeaderLength
|
||||
* Length of embedded user data header, in bytes. The whole header
|
||||
* size will be userDataHeaderLength + 1; 0 for no header.
|
||||
* @param encodedFullBodyLength
|
||||
* Length of the message body when encoded with the given DCS. For
|
||||
* UCS2, in bytes; for 7-bit, in septets.
|
||||
* @param langIndex
|
||||
* Table index used for normal 7-bit encoded character lookup.
|
||||
* @param langShiftIndex
|
||||
* Table index used for escaped 7-bit encoded character lookup.
|
||||
* @param segmentMaxSeq
|
||||
* Max sequence number of a multi-part messages, or 1 for single one.
|
||||
* This number might not be accurate for a multi-part message until
|
||||
* it's processed by #_fragmentText() again.
|
||||
*/
|
||||
_calculateUserDataLength: function _calculateUserDataLength(message) {
|
||||
let options = this._calculateUserDataLength7Bit(message);
|
||||
if (!options) {
|
||||
options = this._calculateUserDataLengthUCS2(message);
|
||||
}
|
||||
|
||||
if (options) {
|
||||
options.fullBody = message;
|
||||
}
|
||||
|
||||
debug("_calculateUserDataLength: " + JSON.stringify(options));
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment GSM 7-Bit encodable string for transmission.
|
||||
*
|
||||
* @param text
|
||||
* text string to be fragmented.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
* @param headerLen
|
||||
* Length of prepended user data header.
|
||||
*
|
||||
* @return an array of objects. See #_fragmentText() for detailed definition.
|
||||
*/
|
||||
_fragmentText7Bit: function _fragmentText7Bit(text, langTable, langShiftTable, headerLen) {
|
||||
const headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
|
||||
const segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT - headerSeptets;
|
||||
let ret = [];
|
||||
let begin = 0, len = 0;
|
||||
for (let i = 0, inc = 0; i < text.length; i++) {
|
||||
let septet = langTable.indexOf(text.charAt(i));
|
||||
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
inc = 1;
|
||||
} else {
|
||||
septet = langShiftTable.indexOf(text.charAt(i));
|
||||
if (septet < 0) {
|
||||
throw new Error("Given text cannot be encoded with GSM 7-bit Alphabet!");
|
||||
}
|
||||
|
||||
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inc = 2;
|
||||
}
|
||||
|
||||
if ((len + inc) > segmentSeptets) {
|
||||
ret.push({
|
||||
body: text.substring(begin, i),
|
||||
encodedBodyLength: len,
|
||||
});
|
||||
begin = i;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
len += inc;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
ret.push({
|
||||
body: text.substring(begin),
|
||||
encodedBodyLength: len,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment UCS2 encodable string for transmission.
|
||||
*
|
||||
* @param text
|
||||
* text string to be fragmented.
|
||||
* @param headerLen
|
||||
* Length of prepended user data header.
|
||||
*
|
||||
* @return an array of objects. See #_fragmentText() for detailed definition.
|
||||
*/
|
||||
_fragmentTextUCS2: function _fragmentTextUCS2(text, headerLen) {
|
||||
const headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2);
|
||||
const segmentChars = RIL.PDU_MAX_USER_DATA_UCS2 - headerChars;
|
||||
let ret = [];
|
||||
for (let offset = 0; offset < text.length; offset += segmentChars) {
|
||||
let str = text.substr(offset, segmentChars);
|
||||
ret.push({
|
||||
body: str,
|
||||
encodedBodyLength: str.length * 2,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment string for transmission.
|
||||
*
|
||||
* Fragment input text string into an array of objects that contains
|
||||
* attributes `body`, substring for this segment, `encodedBodyLength`,
|
||||
* length of the encoded segment body in septets.
|
||||
*
|
||||
* @param text
|
||||
* Text string to be fragmented.
|
||||
* @param options
|
||||
* Optional pre-calculated option object. The output array will be
|
||||
* stored at options.segments if there are multiple segments.
|
||||
*
|
||||
* @return Populated options object.
|
||||
*/
|
||||
_fragmentText: function _fragmentText(text, options) {
|
||||
if (!options) {
|
||||
options = this._calculateUserDataLength(text);
|
||||
}
|
||||
|
||||
if (options.segmentMaxSeq <= 1) {
|
||||
options.segments = null;
|
||||
return options;
|
||||
}
|
||||
|
||||
if (options.dcs == RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
|
||||
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[options.langIndex];
|
||||
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[options.langShiftIndex];
|
||||
options.segments = this._fragmentText7Bit(options.fullBody,
|
||||
langTable, langShiftTable,
|
||||
options.userDataHeaderLength);
|
||||
} else {
|
||||
options.segments = this._fragmentTextUCS2(options.fullBody,
|
||||
options.userDataHeaderLength);
|
||||
}
|
||||
|
||||
// Re-sync options.segmentMaxSeq with actual length of returning array.
|
||||
options.segmentMaxSeq = options.segments.length;
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
getNumberOfMessagesForText: function getNumberOfMessagesForText(text) {
|
||||
//TODO: this assumes 7bit encoding, which is incorrect. Need to look
|
||||
// for characters not supported by 7bit alphabets and then calculate
|
||||
// length in UCS2 encoding.
|
||||
return Math.ceil(text.length / 160);
|
||||
return this._fragmentText(text).segmentMaxSeq;
|
||||
},
|
||||
|
||||
sendSMS: function sendSMS(number, message, requestId, processId) {
|
||||
this.worker.postMessage({type: "sendSMS",
|
||||
number: number,
|
||||
body: message,
|
||||
requestId: requestId,
|
||||
processId: processId});
|
||||
let options = this._calculateUserDataLength(message);
|
||||
options.type = "sendSMS";
|
||||
options.number = number;
|
||||
options.requestId = requestId;
|
||||
options.processId = processId;
|
||||
|
||||
this._fragmentText(message, options);
|
||||
if (options.segmentMaxSeq > 1) {
|
||||
options.segmentRef16Bit = this.segmentRef16Bit;
|
||||
options.segmentRef = this.nextSegmentRef;
|
||||
}
|
||||
|
||||
this.worker.postMessage(options);
|
||||
},
|
||||
|
||||
_callbacks: null,
|
||||
|
@ -413,8 +413,12 @@ const PDU_MTI_SMS_STATUS_COMMAND = 0x02;
|
||||
const PDU_MTI_SMS_SUBMIT = 0x01;
|
||||
const PDU_MTI_SMS_DELIVER = 0x00;
|
||||
|
||||
// User Data max length in octets
|
||||
// User Data max length in septets
|
||||
const PDU_MAX_USER_DATA_7BIT = 160;
|
||||
// User Data max length in octets
|
||||
const PDU_MAX_USER_DATA_8BIT = 140;
|
||||
// User Data max length in chars
|
||||
const PDU_MAX_USER_DATA_UCS2 = 70;
|
||||
|
||||
// DCS - Data Coding Scheme
|
||||
const PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00;
|
||||
|
@ -604,6 +604,13 @@ let RIL = {
|
||||
*/
|
||||
currentDataCalls: {},
|
||||
|
||||
/**
|
||||
* Hash map for received multipart sms fragments. Messages are hashed with
|
||||
* its sender address and concatenation reference number. Three additional
|
||||
* attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
|
||||
*/
|
||||
_receivedSmsSegmentsMap: {},
|
||||
|
||||
/**
|
||||
* Mute or unmute the radio.
|
||||
*/
|
||||
@ -981,9 +988,18 @@ let RIL = {
|
||||
options.SMSC = this.SMSC;
|
||||
|
||||
//TODO: verify values on 'options'
|
||||
//TODO: the data encoding and length in octets should eventually be
|
||||
// computed on the mainthread and passed down to us.
|
||||
GsmPDUHelper.calculateUserDataLength(options);
|
||||
|
||||
if (options.segmentMaxSeq > 1) {
|
||||
if (!options.segmentSeq) {
|
||||
// Fist segment to send
|
||||
options.segmentSeq = 1;
|
||||
options.body = options.segments[0].body;
|
||||
options.encodedBodyLength = options.segments[0].encodedBodyLength;
|
||||
}
|
||||
} else {
|
||||
options.body = options.fullBody;
|
||||
options.encodedBodyLength = options.encodedFullBodyLength;
|
||||
}
|
||||
|
||||
Buf.newParcel(REQUEST_SEND_SMS, options);
|
||||
Buf.writeUint32(2);
|
||||
@ -1369,6 +1385,59 @@ let RIL = {
|
||||
this.muted = Object.getOwnPropertyNames(this.currentCalls).length == 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for processing received multipart SMS.
|
||||
*
|
||||
* @return null for handled segments, and an object containing full message
|
||||
* body once all segments are received.
|
||||
*/
|
||||
_processReceivedSmsSegment: function _processReceivedSmsSegment(original) {
|
||||
let hash = original.sender + ":" + original.header.segmentRef;
|
||||
let seq = original.header.segmentSeq;
|
||||
|
||||
let options = this._receivedSmsSegmentsMap[hash];
|
||||
if (!options) {
|
||||
options = original;
|
||||
this._receivedSmsSegmentsMap[hash] = options;
|
||||
|
||||
options.segmentMaxSeq = original.header.segmentMaxSeq;
|
||||
options.receivedSegments = 0;
|
||||
options.segments = [];
|
||||
} else if (options.segments[seq]) {
|
||||
// Duplicated segment?
|
||||
if (DEBUG) {
|
||||
debug("Got duplicated segment no." + seq + " of a multipart SMS: "
|
||||
+ JSON.stringify(original));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
options.segments[seq] = original.body;
|
||||
options.receivedSegments++;
|
||||
if (options.receivedSegments < options.segmentMaxSeq) {
|
||||
if (DEBUG) {
|
||||
debug("Got segment no." + seq + " of a multipart SMS: "
|
||||
+ JSON.stringify(options));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove from map
|
||||
delete this._receivedSmsSegmentsMap[hash];
|
||||
|
||||
// Rebuild full body
|
||||
options.fullBody = "";
|
||||
for (let i = 1; i <= options.segmentMaxSeq; i++) {
|
||||
options.fullBody += options.segments[i];
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Got full multipart SMS: " + JSON.stringify(options));
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
_handleChangedCallState: function _handleChangedCallState(changedCall) {
|
||||
let message = {type: "callStateChange",
|
||||
call: {callIndex: changedCall.callIndex,
|
||||
@ -1658,6 +1727,20 @@ RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS(length, options) {
|
||||
options.messageRef = Buf.readUint32();
|
||||
options.ackPDU = Buf.readString();
|
||||
options.errorCode = Buf.readUint32();
|
||||
|
||||
//TODO handle errors (bug 727319)
|
||||
if ((options.segmentMaxSeq > 1)
|
||||
&& (options.segmentSeq < options.segmentMaxSeq)) {
|
||||
// Setup attributes for sending next segment
|
||||
let next = options.segmentSeq;
|
||||
options.body = options.segments[next].body;
|
||||
options.encodedBodyLength = options.segments[next].encodedBodyLength;
|
||||
options.segmentSeq = next + 1;
|
||||
|
||||
this.sendSMS(options);
|
||||
return;
|
||||
}
|
||||
|
||||
options.type = "sms-sent";
|
||||
this.sendDOMMessage(options);
|
||||
};
|
||||
@ -1932,8 +2015,16 @@ RIL[UNSOLICITED_RESPONSE_NEW_SMS] = function UNSOLICITED_RESPONSE_NEW_SMS(length
|
||||
}
|
||||
}
|
||||
|
||||
message.type = "sms-received";
|
||||
this.sendDOMMessage(message);
|
||||
if (message.header && (message.header.segmentMaxSeq > 1)) {
|
||||
message = this._processReceivedSmsSegment(message);
|
||||
} else {
|
||||
message.fullBody = message.body;
|
||||
}
|
||||
|
||||
if (message) {
|
||||
message.type = "sms-received";
|
||||
this.sendDOMMessage(message);
|
||||
}
|
||||
|
||||
//TODO: this might be a lie? do we want to wait for the mainthread to
|
||||
// report back?
|
||||
@ -2042,13 +2133,6 @@ RIL[UNSOLICITED_RESEND_INCALL_MUTE] = null;
|
||||
*/
|
||||
let GsmPDUHelper = {
|
||||
|
||||
/**
|
||||
* List of tuples of national language identifier pairs.
|
||||
*/
|
||||
enabledGsmTableTuples: [
|
||||
[PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT],
|
||||
],
|
||||
|
||||
/**
|
||||
* Read one character (2 bytes) from a RIL string and decode as hex.
|
||||
*
|
||||
@ -2369,137 +2453,6 @@ let GsmPDUHelper = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate encoded length using specified locking/single shift table
|
||||
*
|
||||
* @param message
|
||||
* message string to be encoded.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
*
|
||||
* @return encoded length in septets.
|
||||
*
|
||||
* @note that the algorithm used in this function must match exactly with
|
||||
* #writeStringAsSeptets.
|
||||
*/
|
||||
_calculateLangEncodedSeptets: function _calculateLangEncodedSeptets(message, langTable, langShiftTable) {
|
||||
let length = 0;
|
||||
for (let msgIndex = 0; msgIndex < message.length; msgIndex++) {
|
||||
let septet = langTable.indexOf(message.charAt(msgIndex));
|
||||
|
||||
// According to 3GPP TS 23.038, section 6.1.1 General notes, "The
|
||||
// characters marked '1)' are not used but are displayed as a space."
|
||||
if (septet == PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
length++;
|
||||
continue;
|
||||
}
|
||||
|
||||
septet = langShiftTable.indexOf(message.charAt(msgIndex));
|
||||
if (septet == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
||||
// character and therefore must not be used for language specific
|
||||
// characters."
|
||||
if (septet == PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The character is not found in locking shfit table, but could be
|
||||
// encoded as <escape><char> with single shift table. Note that it's
|
||||
// still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE,
|
||||
// but we can display it as a space in this case as said in previous
|
||||
// comment.
|
||||
length += 2;
|
||||
}
|
||||
|
||||
return length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length and its encoding.
|
||||
*
|
||||
* The `options` parameter object should contain the `body` attribute, and
|
||||
* the `dcs`, `userDataHeaderLength`, `encodedBodyLength`, `langIndex`,
|
||||
* `langShiftIndex` attributes will be set as return:
|
||||
*
|
||||
* @param body
|
||||
* String containing the message body.
|
||||
* @param dcs
|
||||
* Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
|
||||
* constants.
|
||||
* @param userDataHeaderLength
|
||||
* Length of embedded user data header, in bytes. The whole header
|
||||
* size will be userDataHeaderLength + 1; 0 for no header.
|
||||
* @param encodedBodyLength
|
||||
* Length of the message body when encoded with the given DCS. For
|
||||
* UCS2, in bytes; for 7-bit, in septets.
|
||||
* @param langIndex
|
||||
* Table index used for normal 7-bit encoded character lookup.
|
||||
* @param langShiftIndex
|
||||
* Table index used for escaped 7-bit encoded character lookup.
|
||||
*/
|
||||
calculateUserDataLength: function calculateUserDataLength(options) {
|
||||
//TODO: support multipart SMS, see bug 712933
|
||||
options.dcs = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
options.langIndex = PDU_NL_IDENTIFIER_DEFAULT;
|
||||
options.langShiftIndex = PDU_NL_IDENTIFIER_DEFAULT;
|
||||
options.encodedBodyLength = 0;
|
||||
options.userDataHeaderLength = 0;
|
||||
|
||||
let needUCS2 = true;
|
||||
let minUserDataSeptets = Number.MAX_VALUE;
|
||||
for (let i = 0; i < this.enabledGsmTableTuples.length; i++) {
|
||||
let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i];
|
||||
|
||||
const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
|
||||
const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
|
||||
|
||||
let bodySeptets = this._calculateLangEncodedSeptets(options.body,
|
||||
langTable,
|
||||
langShiftTable);
|
||||
if (bodySeptets < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let headerLen = 0;
|
||||
if (langIndex != PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langIndex
|
||||
}
|
||||
if (langShiftIndex != PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langShiftIndex
|
||||
}
|
||||
|
||||
// Calculate full user data length, note the extra byte is for header len
|
||||
let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
|
||||
let userDataSeptets = bodySeptets + headerSeptets;
|
||||
if (userDataSeptets >= minUserDataSeptets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
needUCS2 = false;
|
||||
minUserDataSeptets = userDataSeptets;
|
||||
|
||||
options.encodedBodyLength = bodySeptets;
|
||||
options.userDataHeaderLength = headerLen;
|
||||
options.langIndex = langIndex;
|
||||
options.langShiftIndex = langShiftIndex;
|
||||
}
|
||||
|
||||
if (needUCS2) {
|
||||
options.dcs = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
|
||||
options.encodedBodyLength = options.body.length * 2;
|
||||
options.userDataHeaderLength = 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Read 1 + UDHL octets and construct user data header at return.
|
||||
*
|
||||
@ -2528,6 +2481,30 @@ let GsmPDUHelper = {
|
||||
dataAvailable -= 2;
|
||||
|
||||
switch (id) {
|
||||
case PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT: {
|
||||
let ref = this.readHexOctet();
|
||||
let max = this.readHexOctet();
|
||||
let seq = this.readHexOctet();
|
||||
dataAvailable -= 3;
|
||||
if (max && seq && (seq <= max)) {
|
||||
header.segmentRef = ref;
|
||||
header.segmentMaxSeq = max;
|
||||
header.segmentSeq = seq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT: {
|
||||
let ref = (this.readHexOctet() << 8) | this.readHexOctet();
|
||||
let max = this.readHexOctet();
|
||||
let seq = this.readHexOctet();
|
||||
dataAvailable -= 4;
|
||||
if (max && seq && (seq <= max)) {
|
||||
header.segmentRef = ref;
|
||||
header.segmentMaxSeq = max;
|
||||
header.segmentSeq = seq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT:
|
||||
let langShiftIndex = this.readHexOctet();
|
||||
--dataAvailable;
|
||||
@ -2582,6 +2559,20 @@ let GsmPDUHelper = {
|
||||
writeUserDataHeader: function writeUserDataHeader(options) {
|
||||
this.writeHexOctet(options.userDataHeaderLength);
|
||||
|
||||
if (options.segmentMaxSeq > 1) {
|
||||
if (options.segmentRef16Bit) {
|
||||
this.writeHexOctet(PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT);
|
||||
this.writeHexOctet(4);
|
||||
this.writeHexOctet((options.segmentRef >> 8) & 0xFF);
|
||||
} else {
|
||||
this.writeHexOctet(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT);
|
||||
this.writeHexOctet(3);
|
||||
}
|
||||
this.writeHexOctet(options.segmentRef & 0xFF);
|
||||
this.writeHexOctet(options.segmentMaxSeq & 0xFF);
|
||||
this.writeHexOctet(options.segmentSeq & 0xFF);
|
||||
}
|
||||
|
||||
if (options.langIndex != PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
this.writeHexOctet(PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT);
|
||||
this.writeHexOctet(1);
|
||||
@ -2598,8 +2589,17 @@ let GsmPDUHelper = {
|
||||
/**
|
||||
* User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit
|
||||
* (UCS2) data.
|
||||
*
|
||||
* @param msg
|
||||
* message object for output.
|
||||
* @param length
|
||||
* length of user data to read in octets.
|
||||
* @param codingScheme
|
||||
* coding scheme used to decode user data.
|
||||
* @param hasHeader
|
||||
* whether a header is embedded.
|
||||
*/
|
||||
readUserData: function readUserData(length, codingScheme, hasHeader) {
|
||||
readUserData: function readUserData(msg, length, codingScheme, hasHeader) {
|
||||
if (DEBUG) {
|
||||
debug("Reading " + length + " bytes of user data.");
|
||||
debug("Coding scheme: " + codingScheme);
|
||||
@ -2636,43 +2636,45 @@ let GsmPDUHelper = {
|
||||
break;
|
||||
}
|
||||
|
||||
let header;
|
||||
if (DEBUG) debug("PDU: message encoding is " + encoding + " bit.");
|
||||
|
||||
let paddingBits = 0;
|
||||
if (hasHeader) {
|
||||
header = this.readUserDataHeader();
|
||||
msg.header = this.readUserDataHeader();
|
||||
|
||||
if (encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
|
||||
let headerBits = (header.length + 1) * 8;
|
||||
let headerBits = (msg.header.length + 1) * 8;
|
||||
let headerSeptets = Math.ceil(headerBits / 7);
|
||||
|
||||
length -= headerSeptets;
|
||||
paddingBits = headerSeptets * 7 - headerBits;
|
||||
} else {
|
||||
length -= (header.length + 1);
|
||||
length -= (msg.header.length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) debug("PDU: message encoding is " + encoding + " bit.");
|
||||
msg.body = null;
|
||||
switch (encoding) {
|
||||
case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
|
||||
// 7 bit encoding allows 140 octets, which means 160 characters
|
||||
// ((140x8) / 7 = 160 chars)
|
||||
if (length > PDU_MAX_USER_DATA_7BIT) {
|
||||
if (DEBUG) debug("PDU error: user data is too long: " + length);
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
|
||||
return this.readSeptetsToString(length,
|
||||
paddingBits,
|
||||
hasHeader ? header.langIndex : PDU_NL_IDENTIFIER_DEFAULT,
|
||||
hasHeader ? header.langShiftIndex : PDU_NL_IDENTIFIER_DEFAULT);
|
||||
let langIndex = hasHeader ? msg.header.langIndex : PDU_NL_IDENTIFIER_DEFAULT;
|
||||
let langShiftIndex = hasHeader ? msg.header.langShiftIndex : PDU_NL_IDENTIFIER_DEFAULT;
|
||||
msg.body = this.readSeptetsToString(length, paddingBits, langIndex,
|
||||
langShiftIndex);
|
||||
break;
|
||||
case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
|
||||
// Unsupported.
|
||||
return null;
|
||||
break;
|
||||
case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
|
||||
return this.readUCS2String(length);
|
||||
msg.body = this.readUCS2String(length);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2786,9 +2788,8 @@ let GsmPDUHelper = {
|
||||
|
||||
// - TP-User-Data -
|
||||
if (userDataLength > 0) {
|
||||
msg.body = this.readUserData(userDataLength,
|
||||
dataCodingScheme,
|
||||
hasUserDataHeader);
|
||||
this.readUserData(msg, userDataLength, dataCodingScheme,
|
||||
hasUserDataHeader);
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
@ -119,6 +119,20 @@ function newIncomingParcel(fakeParcelSize, response, request, data) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function newRadioInterfaceLayer() {
|
||||
let ril_ns = {
|
||||
ChromeWorker: function ChromeWorker() {
|
||||
// Stub function
|
||||
},
|
||||
};
|
||||
|
||||
subscriptLoader.loadSubScript("resource://gre/components/RadioInterfaceLayer.js", ril_ns);
|
||||
return new ril_ns.RadioInterfaceLayer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether specified function throws exception with expected
|
||||
* result.
|
||||
|
@ -55,10 +55,12 @@ add_test(function test_nl_single_shift_tables_validity() {
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify GsmPDUHelper#_calculateLangEncodedSeptets() and
|
||||
* Verify RadioInterfaceLayer#_countGsm7BitSeptets() and
|
||||
* GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
|
||||
*/
|
||||
add_test(function test_GsmPDUHelper__calculateLangEncodedSeptets() {
|
||||
add_test(function test_RadioInterfaceLayer__countGsm7BitSeptets() {
|
||||
let ril = newRadioInterfaceLayer();
|
||||
|
||||
let worker = newWorker({
|
||||
postRILMessage: function fakePostRILMessage(data) {
|
||||
// Do nothing
|
||||
@ -78,9 +80,9 @@ add_test(function test_GsmPDUHelper__calculateLangEncodedSeptets() {
|
||||
|
||||
function do_check_calc(str, expectedCalcLen, lst, sst) {
|
||||
do_check_eq(expectedCalcLen,
|
||||
helper._calculateLangEncodedSeptets(str,
|
||||
PDU_NL_LOCKING_SHIFT_TABLES[lst],
|
||||
PDU_NL_SINGLE_SHIFT_TABLES[sst]));
|
||||
ril._countGsm7BitSeptets(str,
|
||||
PDU_NL_LOCKING_SHIFT_TABLES[lst],
|
||||
PDU_NL_SINGLE_SHIFT_TABLES[sst]));
|
||||
|
||||
helper.resetOctetWritten();
|
||||
helper.writeStringAsSeptets(str, 0, lst, sst);
|
||||
@ -131,28 +133,18 @@ add_test(function test_GsmPDUHelper__calculateLangEncodedSeptets() {
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify GsmPDUHelper#calculateUserDataLength handles national language
|
||||
* Verify RadioInterfaceLayer#calculateUserDataLength handles national language
|
||||
* selection correctly.
|
||||
*/
|
||||
add_test(function test_GsmPDUHelper_calculateUserDataLength() {
|
||||
let worker = newWorker({
|
||||
postRILMessage: function fakePostRILMessage(data) {
|
||||
// Do nothing
|
||||
},
|
||||
postMessage: function fakePostMessage(message) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
add_test(function test_RadioInterfaceLayer__calculateUserDataLength() {
|
||||
let ril = newRadioInterfaceLayer();
|
||||
|
||||
let helper = worker.GsmPDUHelper;
|
||||
let calc = helper.calculateUserDataLength;
|
||||
function test_calc(str, expected, enabledGsmTableTuples) {
|
||||
helper.enabledGsmTableTuples = enabledGsmTableTuples;
|
||||
let options = {body: str};
|
||||
calc.call(helper, options);
|
||||
ril.enabledGsmTableTuples = enabledGsmTableTuples;
|
||||
let options = ril._calculateUserDataLength(str);
|
||||
|
||||
do_check_eq(expected[0], options.dcs);
|
||||
do_check_eq(expected[1], options.encodedBodyLength);
|
||||
do_check_eq(expected[1], options.encodedFullBodyLength);
|
||||
do_check_eq(expected[2], options.userDataHeaderLength);
|
||||
do_check_eq(expected[3], options.langIndex);
|
||||
do_check_eq(expected[4], options.langShiftIndex);
|
||||
@ -160,9 +152,9 @@ add_test(function test_GsmPDUHelper_calculateUserDataLength() {
|
||||
|
||||
// Test UCS fallback
|
||||
// - No any default enabled nl tables
|
||||
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0, 0, 0], []);
|
||||
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], []);
|
||||
// - Character not defined in enabled nl tables
|
||||
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0, 0, 0], [[2, 2]]);
|
||||
test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], [[2, 2]]);
|
||||
|
||||
// With GSM default nl tables
|
||||
test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
|
||||
@ -211,6 +203,101 @@ add_test(function test_GsmPDUHelper_calculateUserDataLength() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function generateStringOfLength(str, length) {
|
||||
while (str.length < length) {
|
||||
if (str.length < (length / 2)) {
|
||||
str = str + str;
|
||||
} else {
|
||||
str = str + str.substr(0, length - str.length);
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify RadioInterfaceLayer#_calculateUserDataLength7Bit multipart handling.
|
||||
*/
|
||||
add_test(function test_RadioInterfaceLayer__calculateUserDataLength7Bit_multipart() {
|
||||
let ril = newRadioInterfaceLayer();
|
||||
|
||||
function test_calc(str, expected) {
|
||||
let options = ril._calculateUserDataLength7Bit(str);
|
||||
|
||||
do_check_eq(expected[0], options.encodedFullBodyLength);
|
||||
do_check_eq(expected[1], options.userDataHeaderLength);
|
||||
do_check_eq(expected[2], options.segmentMaxSeq);
|
||||
}
|
||||
|
||||
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT),
|
||||
[PDU_MAX_USER_DATA_7BIT, 0, 1]);
|
||||
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1),
|
||||
[PDU_MAX_USER_DATA_7BIT + 1, 5, 2]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify RadioInterfaceLayer#_fragmentText7Bit().
|
||||
*/
|
||||
add_test(function test_RadioInterfaceLayer__fragmentText7Bit() {
|
||||
let ril = newRadioInterfaceLayer();
|
||||
|
||||
function test_calc(str, expected) {
|
||||
let options = ril._fragmentText(str);
|
||||
if (expected) {
|
||||
do_check_eq(expected, options.segments.length);
|
||||
} else {
|
||||
do_check_eq(null, options.segments);
|
||||
}
|
||||
}
|
||||
|
||||
// Boundary checks
|
||||
test_calc("");
|
||||
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT));
|
||||
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), 2);
|
||||
|
||||
// Escaped character
|
||||
test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2));
|
||||
test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2 + 1), 2);
|
||||
// Escaped character cannot be separated
|
||||
test_calc(generateStringOfLength("{", (PDU_MAX_USER_DATA_7BIT - 7) * 2 / 2), 3);
|
||||
|
||||
// Test headerLen, 7 = Math.ceil(6 * 8 / 7), 6 = headerLen + 1
|
||||
test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT - 7));
|
||||
test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 2), 2);
|
||||
test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 3), 3);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify RadioInterfaceLayer#_fragmentTextUCS2().
|
||||
*/
|
||||
add_test(function test_RadioInterfaceLayer__fragmentTextUCS2() {
|
||||
let ril = newRadioInterfaceLayer();
|
||||
|
||||
function test_calc(str, expected) {
|
||||
let options = ril._fragmentText(str);
|
||||
if (expected) {
|
||||
do_check_eq(expected, options.segments.length);
|
||||
} else {
|
||||
do_check_eq(null, options.segments);
|
||||
}
|
||||
}
|
||||
|
||||
// Boundary checks
|
||||
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2));
|
||||
test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), 2);
|
||||
|
||||
// UCS2 character cannot be separated
|
||||
ril.segmentRef16Bit = true;
|
||||
test_calc(generateStringOfLength("\ua2db", (PDU_MAX_USER_DATA_UCS2 * 2 - 7) * 2 / 2), 3);
|
||||
ril.segmentRef16Bit = false;
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
|
||||
*/
|
||||
@ -386,6 +473,8 @@ function add_test_receiving_sms(expected, pdu) {
|
||||
}
|
||||
|
||||
function test_receiving_7bit_alphabets(lst, sst) {
|
||||
let ril = newRadioInterfaceLayer();
|
||||
|
||||
let worker = newWriteHexOctetAsUint8Worker();
|
||||
let helper = worker.GsmPDUHelper;
|
||||
let buf = worker.Buf;
|
||||
@ -405,8 +494,7 @@ function test_receiving_7bit_alphabets(lst, sst) {
|
||||
for (let i = 0; i < text.length;) {
|
||||
let len = Math.min(70, text.length - i);
|
||||
let expected = text.substring(i, i + len);
|
||||
let septets = helper._calculateLangEncodedSeptets(expected, langTable,
|
||||
langShiftTable);
|
||||
let septets = ril._countGsm7BitSeptets(expected, langTable, langShiftTable);
|
||||
let rawBytes = get7bitRawBytes(expected);
|
||||
let pdu = compose7bitPdu(lst, sst, rawBytes, septets);
|
||||
add_test_receiving_sms(expected, pdu);
|
||||
|
@ -79,7 +79,7 @@ TelephonyCall::ChangeStateInternal(PRUint16 aCallState, bool aFireEvents)
|
||||
stateString.AssignLiteral("dialing");
|
||||
break;
|
||||
case nsIRadioInterfaceLayer::CALL_STATE_ALERTING:
|
||||
stateString.AssignLiteral("ringing");
|
||||
stateString.AssignLiteral("alerting");
|
||||
break;
|
||||
case nsIRadioInterfaceLayer::CALL_STATE_BUSY:
|
||||
stateString.AssignLiteral("busy");
|
||||
@ -158,7 +158,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TelephonyCall,
|
||||
Telephony, "mTelephony")
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(statechange)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(dialing)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(ringing)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(alerting)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(busy)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connecting)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connected)
|
||||
@ -172,7 +172,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TelephonyCall,
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTelephony)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(statechange)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(dialing)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(ringing)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(alerting)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(busy)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connecting)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connected)
|
||||
@ -240,7 +240,7 @@ TelephonyCall::HangUp()
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, statechange)
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, dialing)
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, ringing)
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, alerting)
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, busy)
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, connecting)
|
||||
NS_IMPL_EVENT_HANDLER(TelephonyCall, connected)
|
||||
|
@ -54,7 +54,7 @@ class TelephonyCall : public nsDOMEventTargetHelper,
|
||||
{
|
||||
NS_DECL_EVENT_HANDLER(statechange)
|
||||
NS_DECL_EVENT_HANDLER(dialing)
|
||||
NS_DECL_EVENT_HANDLER(ringing)
|
||||
NS_DECL_EVENT_HANDLER(alerting)
|
||||
NS_DECL_EVENT_HANDLER(busy)
|
||||
NS_DECL_EVENT_HANDLER(connecting)
|
||||
NS_DECL_EVENT_HANDLER(connected)
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
|
||||
[scriptable, builtinclass, uuid(832b7551-ff53-403f-9e2c-d7d28e2bb40b)]
|
||||
[scriptable, builtinclass, uuid(f741d52a-38bd-48f8-838b-cf4cd74a6ea5)]
|
||||
interface nsIDOMTelephonyCall : nsIDOMEventTarget
|
||||
{
|
||||
readonly attribute DOMString number;
|
||||
@ -54,7 +54,7 @@ interface nsIDOMTelephonyCall : nsIDOMEventTarget
|
||||
attribute nsIDOMEventListener onstatechange;
|
||||
|
||||
attribute nsIDOMEventListener ondialing;
|
||||
attribute nsIDOMEventListener onringing;
|
||||
attribute nsIDOMEventListener onalerting;
|
||||
attribute nsIDOMEventListener onbusy;
|
||||
attribute nsIDOMEventListener onconnecting;
|
||||
attribute nsIDOMEventListener onconnected;
|
||||
|
@ -1 +1 @@
|
||||
http://hg.mozilla.org/projects/addon-sdk/archive/28b4f9e190e3.tar.bz2
|
||||
http://hg.mozilla.org/projects/addon-sdk/archive/3ce8a0112619.tar.bz2
|
||||
|
@ -31,11 +31,13 @@
|
||||
login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
|
||||
login2.init("http://mochi.test:8888", null, "mochirealm", "user1name", "user1pass", "", "");
|
||||
pwmgr.addLogin(login2);
|
||||
startCallbackTimer();
|
||||
}
|
||||
function cleanup() {
|
||||
var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
|
||||
pwmgr.removeLogin(login);
|
||||
pwmgr.removeLogin(login2);
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
function makeXHR(expectedStatus, expectedText, extra) {
|
||||
@ -59,7 +61,6 @@
|
||||
function testNonAnonymousCredentials() {
|
||||
var xhr = makeXHR(200, "OK");
|
||||
xhr.send();
|
||||
startCallbackTimer();
|
||||
}
|
||||
|
||||
function testAnonymousCredentials() {
|
||||
@ -77,10 +78,14 @@
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
var gExpectedDialogs = 0;
|
||||
var gCurrentTest;
|
||||
function runNextTest() {
|
||||
is(gExpectedDialogs, 0, "received expected number of auth dialogs");
|
||||
Cc["@mozilla.org/network/http-auth-manager;1"].getService(Components.interfaces.nsIHttpAuthManager).clearAll();
|
||||
if (pendingTests.length > 0) {
|
||||
gCurrentTest = pendingTests.shift();
|
||||
({expectedDialogs: gExpectedDialogs,
|
||||
test: gCurrentTest}) = pendingTests.shift();
|
||||
gCurrentTest.call(this);
|
||||
} else {
|
||||
cleanup();
|
||||
@ -88,8 +93,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
var pendingTests = [testNonAnonymousCredentials, testAnonymousCredentials,
|
||||
testAnonymousNoAuth];
|
||||
var pendingTests = [{expectedDialogs: 2, test: testNonAnonymousCredentials},
|
||||
{expectedDialogs: 1, test: testAnonymousCredentials},
|
||||
{expectedDialogs: 0, test: testAnonymousNoAuth}];
|
||||
init();
|
||||
runNextTest();
|
||||
|
||||
@ -97,9 +103,8 @@
|
||||
{
|
||||
var dialog = doc.getElementById("commonDialog");
|
||||
dialog.acceptDialog();
|
||||
if (gCurrentTest == testNonAnonymousCredentials) {
|
||||
startCallbackTimer();
|
||||
}
|
||||
gExpectedDialogs--;
|
||||
startCallbackTimer();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
@ -234,13 +234,12 @@ PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data,
|
||||
PRUint32 nbytes;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (entrySize > 10 * sizeof(void *)) {
|
||||
if (entrySize > 16 * sizeof(void *)) {
|
||||
printf_stderr(
|
||||
"pldhash: for the table at address %p, the given entrySize"
|
||||
" of %lu %s favors chaining over double hashing.\n",
|
||||
" of %lu definitely favors chaining over double hashing.\n",
|
||||
(void *) table,
|
||||
(unsigned long) entrySize,
|
||||
(entrySize > 16 * sizeof(void*)) ? "definitely" : "probably");
|
||||
(unsigned long) entrySize);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user