Bug 749856 - Part 3: handle WAP Push notification, r=philikon

This commit is contained in:
Vicamo Yang 2012-06-01 16:48:47 +08:00
parent a4c9c039b9
commit 3144699fbf
10 changed files with 360 additions and 5 deletions

View File

@ -650,10 +650,18 @@ SettingsListener.observe('language.current', 'en-US', function(value) {
});
});
['ril.data.apn', 'ril.data.user', 'ril.data.passwd'].forEach(function(key) {
let strPrefs = ['ril.data.apn', 'ril.data.user', 'ril.data.passwd',
'ril.data.mmsc', 'ril.data.mmsproxy'];
strPrefs.forEach(function(key) {
SettingsListener.observe(key, false, function(value) {
Services.prefs.setCharPref(key, value);
});
});
['ril.data.mmsport'].forEach(function(key) {
SettingsListener.observe(key, false, function(value) {
Services.prefs.setIntPref(key, value);
});
});
})();

View File

@ -173,6 +173,9 @@
@BINPATH@/components/dom_indexeddb.xpt
@BINPATH@/components/dom_offline.xpt
@BINPATH@/components/dom_json.xpt
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_mms.xpt
#endif
@BINPATH@/components/dom_power.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_settings.xpt
@ -424,6 +427,8 @@
@BINPATH@/components/NetworkManager.js
@BINPATH@/components/RadioInterfaceLayer.manifest
@BINPATH@/components/RadioInterfaceLayer.js
@BINPATH@/components/MmsService.manifest
@BINPATH@/components/MmsService.js
@BINPATH@/components/RILContentHelper.js
@BINPATH@/components/SmsDatabaseService.manifest
@BINPATH@/components/SmsDatabaseService.js

View File

@ -178,6 +178,9 @@
@BINPATH@/components/dom_indexeddb.xpt
@BINPATH@/components/dom_offline.xpt
@BINPATH@/components/dom_json.xpt
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_mms.xpt
#endif
@BINPATH@/components/dom_power.xpt
@BINPATH@/components/dom_range.xpt
@BINPATH@/components/dom_settings.xpt
@ -407,6 +410,8 @@
#ifdef MOZ_B2G_RIL
@BINPATH@/components/RadioInterfaceLayer.manifest
@BINPATH@/components/RadioInterfaceLayer.js
@BINPATH@/components/MmsService.manifest
@BINPATH@/components/MmsService.js
@BINPATH@/components/RILContentHelper.js
@BINPATH@/components/SmsDatabaseService.manifest
@BINPATH@/components/SmsDatabaseService.js

View File

@ -11,7 +11,7 @@ relativesrcdir = dom/mms
include $(DEPTH)/config/autoconf.mk
PARALLEL_DIRS = src
PARALLEL_DIRS = interfaces src
ifdef ENABLE_TESTS
XPCSHELL_TESTS = tests

View File

@ -0,0 +1,19 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
XPIDL_MODULE = dom_mms
XPIDLSRCS = \
nsIMmsService.idl \
nsIWapPushApplication.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* Handle WAP Push notifications.
*/
[scriptable, uuid(fd6f7f6b-a67e-4892-930d-fca864df8fe7)]
interface nsIWapPushApplication : nsISupports
{
/**
* Receive WAP Push message.
*
* @param aData
* An array containing raw PDU data.
* @param aLength
* Length of aData.
* @param aOffset
* Start offset of aData containing message body of the Push PDU.
* @param options
* An object containing various attributes from lower transport layer.
*/
[implicit_jscontext]
void receiveWapPush([array, size_is(aLength)] in octet aData,
in unsigned long aLength,
in unsigned long aOffset,
in jsval aOptions);
};

View File

@ -12,6 +12,11 @@ VPATH = \
include $(DEPTH)/config/autoconf.mk
ifdef MOZ_B2G_RIL
EXTRA_COMPONENTS = \
ril/MmsService.js \
ril/MmsService.manifest \
$(NULL)
EXTRA_JS_MODULES = \
ril/mms_consts.js \
ril/MmsPduHelper.jsm \

View File

@ -0,0 +1,270 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const RIL_MMSSERVICE_CONTRACTID = "@mozilla.org/mms/rilmmsservice;1";
const RIL_MMSSERVICE_CID = Components.ID("{217ddd76-75db-4210-955d-8806cd8d87f9}");
const DEBUG = false;
const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
// HTTP status codes:
// @see http://tools.ietf.org/html/rfc2616#page-39
const HTTP_STATUS_OK = 200;
XPCOMUtils.defineLazyServiceGetter(this, "gpps",
"@mozilla.org/network/protocol-proxy-service;1",
"nsIProtocolProxyService");
XPCOMUtils.defineLazyGetter(this, "MMS", function () {
let MMS = {};
Cu.import("resource://gre/modules/MmsPduHelper.jsm", MMS);
return MMS;
});
/**
* MmsService
*/
function MmsService() {
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
Services.obs.addObserver(this, kNetworkInterfaceStateChangedTopic, false);
}
MmsService.prototype = {
classID: RIL_MMSSERVICE_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMmsService,
Ci.nsIWapPushApplication,
Ci.nsIObserver,
Ci.nsIProtocolProxyFilter]),
proxyInfo: null,
MMSC: null,
/** MMS proxy filter reference count. */
proxyFilterRefCount: 0,
/**
* Acquire referece-counted MMS proxy filter.
*/
acquireProxyFilter: function acquireProxyFilter() {
if (!this.proxyFilterRefCount) {
debug("Register proxy filter");
gpps.registerFilter(this, 0);
}
this.proxyFilterRefCount++;
},
/**
* Release referece-counted MMS proxy filter.
*/
releaseProxyFilter: function releaseProxyFilter() {
this.proxyFilterRefCount--;
if (this.proxyFilterRefCount <= 0) {
this.proxyFilterRefCount = 0;
debug("Unregister proxy filter");
gpps.unregisterFilter(this);
}
},
/**
* Send MMS request to MMSC.
*
* @param method
* "GET" or "POST".
* @param url
* Target url string.
* @param callback
* A callback function that takes two arguments: one for http status,
* the other for wrapped PDU data for further parsing.
*/
sendMmsRequest: function sendMmsRequest(method, url, callback) {
let that = this;
function releaseProxyFilterAndCallback(status, data) {
// Always release proxy filter before callback.
that.releaseProxyFilter(false);
if (callback) {
callback(status, data);
}
}
this.acquireProxyFilter();
try {
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
// Basic setups
xhr.open(method, url, true);
xhr.responseType = "arraybuffer";
xhr.setRequestHeader("Content-Length", 0);
// Setup event listeners
xhr.onerror = function () {
debug("xhr error, response headers: " + xhr.getAllResponseHeaders());
releaseProxyFilterAndCallback(xhr.status, null);
};
xhr.onreadystatechange = function () {
if (xhr.readyState != Ci.nsIXMLHttpRequest.DONE) {
return;
}
let data = null;
switch (xhr.status) {
case HTTP_STATUS_OK: {
debug("xhr success, response headers: " + xhr.getAllResponseHeaders());
let array = new Uint8Array(xhr.response);
if (false) {
for (let begin = 0; begin < array.length; begin += 20) {
debug("res: " + JSON.stringify(array.subarray(begin, begin + 20)));
}
}
data = {array: array, offset: 0};
break;
}
default: {
debug("xhr done, but status = " + xhr.status);
break;
}
}
releaseProxyFilterAndCallback(xhr.status, data);
}
// Send request
xhr.send();
} catch (e) {
debug("xhr error, can't send: " + e.message);
releaseProxyFilterAndCallback(0, null);
}
},
/**
* @param data
* A wrapped object containing raw PDU data.
*/
parseStreamAndDispatch: function parseStreamAndDispatch(data) {
let msg = MMS.PduHelper.parse(data, null);
if (!msg) {
return;
}
debug("parseStreamAndDispatch: msg = " + JSON.stringify(msg));
switch (msg.type) {
case MMS.MMS_PDU_TYPE_NOTIFICATION_IND:
this.handleNotificationIndication(msg);
break;
default:
debug("Unsupported X-MMS-Message-Type: " + msg.type);
break;
}
},
/**
* Handle incoming M-Notification.ind PDU.
*
* @param msg
* The MMS message object.
*/
handleNotificationIndication: function handleNotificationIndication(msg) {
let url = msg.headers["x-mms-content-location"].uri;
this.sendMmsRequest("GET", url, (function (status, data) {
if (data) {
this.parseStreamAndDispatch(data);
}
}).bind(this));
},
/**
* Update proxyInfo & MMSC from preferences.
*
* @param enabled
* Enable or disable MMS proxy.
*/
updateProxyInfo: function updateProxyInfo(enabled) {
try {
if (enabled) {
this.MMSC = Services.prefs.getCharPref("ril.data.mmsc");
this.proxyInfo = gpps.newProxyInfo("http",
Services.prefs.getCharPref("ril.data.mmsproxy"),
Services.prefs.getIntPref("ril.data.mmsport"),
Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST,
-1, null);
debug("updateProxyInfo: "
+ JSON.stringify({MMSC: this.MMSC, proxyInfo: this.proxyInfo}));
return;
}
} catch (e) {
// Failed to refresh proxy info from settings. Fallback to disable.
}
this.MMSC = null;
this.proxyInfo = null;
},
// nsIMmsService
hasSupport: function hasSupport() {
return true;
},
// nsIWapPushApplication
receiveWapPush: function receiveWapPush(array, length, offset, options) {
this.parseStreamAndDispatch({array: array, offset: offset});
},
// nsIObserver
observe: function observe(subject, topic, data) {
switch (topic) {
case kNetworkInterfaceStateChangedTopic: {
let iface = subject.QueryInterface(Ci.nsINetworkInterface);
if ((iface.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE)
|| (iface.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS)) {
this.updateProxyInfo(iface.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED);
}
break;
}
case kXpcomShutdownObserverTopic: {
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
Services.obs.removeObserver(this, kNetworkInterfaceStateChangedTopic);
break;
}
}
},
// nsIProtocolProxyFilter
applyFilter: function applyFilter(service, uri, proxyInfo) {
if (uri.prePath == this.MMSC) {
debug("applyFilter: match " + uri.spec);
return this.proxyInfo;
}
return proxyInfo;
},
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([MmsService]);
let debug;
if (DEBUG) {
debug = function (s) {
dump("-@- MmsService: " + s + "\n");
};
} else {
debug = function (s) {};
}

View File

@ -0,0 +1,4 @@
# MmsService.js
component {217ddd76-75db-4210-955d-8806cd8d87f9} MmsService.js
contract @mozilla.org/mms/rilmmsservice;1 {217ddd76-75db-4210-955d-8806cd8d87f9}
category profile-after-change MmsService @mozilla.org/mms/rilmmsservice;1

View File

@ -6,6 +6,9 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/WspPduHelper.jsm");
const DEBUG = false; // set to true to see debug messages
@ -38,9 +41,14 @@ let WapPushManager = {
return;
}
// FIXME: hand over to others
debug("No WAP Push application registered for " + appid);
if (appid == "x-wap-application:mms.ua") {
let mmsService = Cc["@mozilla.org/mms/rilmmsservice;1"]
.getService(Ci.nsIMmsService);
mmsService.QueryInterface(Ci.nsIWapPushApplication)
.receiveWapPush(data.array, data.array.length, data.offset, options);
} else {
debug("No WAP Push application registered for " + appid);
}
},
/**