michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/PhoneNumberUtils.jsm"); michael@0: Cu.import("resource://gre/modules/WspPduHelper.jsm", this); michael@0: michael@0: const DEBUG = false; // set to true to see debug messages michael@0: michael@0: /** michael@0: * WAP Push decoders michael@0: */ michael@0: XPCOMUtils.defineLazyGetter(this, "SI", function () { michael@0: let SI = {}; michael@0: Cu.import("resource://gre/modules/SiPduHelper.jsm", SI); michael@0: return SI; michael@0: }); michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "SL", function () { michael@0: let SL = {}; michael@0: Cu.import("resource://gre/modules/SlPduHelper.jsm", SL); michael@0: return SL; michael@0: }); michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "CP", function () { michael@0: let CP = {}; michael@0: Cu.import("resource://gre/modules/CpPduHelper.jsm", CP); michael@0: return CP; michael@0: }); michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", michael@0: "@mozilla.org/system-message-internal;1", michael@0: "nsISystemMessagesInternal"); michael@0: XPCOMUtils.defineLazyServiceGetter(this, "gRIL", michael@0: "@mozilla.org/ril;1", michael@0: "nsIRadioInterfaceLayer"); michael@0: michael@0: /** michael@0: * Helpers for WAP PDU processing. michael@0: */ michael@0: this.WapPushManager = { michael@0: michael@0: /** michael@0: * Parse raw PDU data and deliver to a proper target. michael@0: * michael@0: * @param data michael@0: * A wrapped object containing raw PDU data. michael@0: * @param options michael@0: * Extra context for decoding. michael@0: */ michael@0: processMessage: function processMessage(data, options) { michael@0: try { michael@0: PduHelper.parse(data, true, options); michael@0: debug("options: " + JSON.stringify(options)); michael@0: } catch (ex) { michael@0: debug("Failed to parse sessionless WSP PDU: " + ex.message); michael@0: return; michael@0: } michael@0: michael@0: let appid = options.headers["x-wap-application-id"]; michael@0: if (!appid) { michael@0: // Assume message without applicatioin ID is WAP Push michael@0: debug("Push message doesn't contains X-Wap-Application-Id."); michael@0: } michael@0: michael@0: // MMS michael@0: if (appid == "x-wap-application:mms.ua") { michael@0: let mmsService = Cc["@mozilla.org/mms/rilmmsservice;1"] michael@0: .getService(Ci.nsIMmsService); michael@0: mmsService.QueryInterface(Ci.nsIWapPushApplication) michael@0: .receiveWapPush(data.array, data.array.length, data.offset, options); michael@0: return; michael@0: } michael@0: michael@0: /** michael@0: * Non-MMS, handled according to content type michael@0: * michael@0: * WAP Type content-type x-wap-application-id michael@0: * MMS "application/vnd.wap.mms-message" "x-wap-application:mms.ua" michael@0: * SI "text/vnd.wap.si" "x-wap-application:wml.ua" michael@0: * SI(WBXML) "application/vnd.wap.sic" "x-wap-application:wml.ua" michael@0: * SL "text/vnd.wap.sl" "x-wap-application:wml.ua" michael@0: * SL(WBXML) "application/vnd.wap.slc" "x-wap-application:wml.ua" michael@0: * Provisioning "text/vnd.wap.connectivity-xml" "x-wap-application:wml.ua" michael@0: * Provisioning(WBXML) "application/vnd.wap.connectivity-wbxml" "x-wap-application:wml.ua" michael@0: * michael@0: * @see http://technical.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx michael@0: */ michael@0: let contentType = options.headers["content-type"].media; michael@0: let msg; michael@0: let authInfo = null; michael@0: michael@0: if (contentType === "text/vnd.wap.si" || michael@0: contentType === "application/vnd.wap.sic") { michael@0: msg = SI.PduHelper.parse(data, contentType); michael@0: } else if (contentType === "text/vnd.wap.sl" || michael@0: contentType === "application/vnd.wap.slc") { michael@0: msg = SL.PduHelper.parse(data, contentType); michael@0: } else if (contentType === "text/vnd.wap.connectivity-xml" || michael@0: contentType === "application/vnd.wap.connectivity-wbxml") { michael@0: // Apply HMAC authentication on WBXML encoded CP message. michael@0: if (contentType === "application/vnd.wap.connectivity-wbxml") { michael@0: let params = options.headers["content-type"].params; michael@0: let sec = params && params.sec; michael@0: let mac = params && params.mac; michael@0: authInfo = CP.Authenticator.check(data.array.subarray(data.offset), michael@0: sec, mac, function getNetworkPin() { michael@0: let imsi = gRIL.getRadioInterface(options.serviceId).rilContext.imsi; michael@0: return CP.Authenticator.formatImsi(imsi); michael@0: }); michael@0: } michael@0: michael@0: msg = CP.PduHelper.parse(data, contentType); michael@0: } else { michael@0: // Unsupported type, provide raw data. michael@0: msg = { michael@0: contentType: contentType, michael@0: content: data.array michael@0: }; michael@0: msg.content.length = data.array.length; michael@0: } michael@0: michael@0: let sender = PhoneNumberUtils.normalize(options.sourceAddress, false); michael@0: let parsedSender = PhoneNumberUtils.parse(sender); michael@0: if (parsedSender && parsedSender.internationalNumber) { michael@0: sender = parsedSender.internationalNumber; michael@0: } michael@0: michael@0: gSystemMessenger.broadcastMessage("wappush-received", { michael@0: sender: sender, michael@0: contentType: msg.contentType, michael@0: content: msg.content, michael@0: authInfo: authInfo, michael@0: serviceId: options.serviceId michael@0: }); michael@0: }, michael@0: michael@0: /** michael@0: * @param array michael@0: * A Uint8Array or an octet array representing raw PDU data. michael@0: * @param length michael@0: * Length of the array. michael@0: * @param offset michael@0: * Offset of the array that a raw PDU data begins. michael@0: * @param options michael@0: * WDP bearer information. michael@0: */ michael@0: receiveWdpPDU: function receiveWdpPDU(array, length, offset, options) { michael@0: if ((options.bearer == null) || !options.sourceAddress michael@0: || (options.sourcePort == null) || !array) { michael@0: debug("Incomplete WDP PDU"); michael@0: return; michael@0: } michael@0: michael@0: if (options.destinationPort != WDP_PORT_PUSH) { michael@0: debug("Not WAP Push port: " + options.destinationPort); michael@0: return; michael@0: } michael@0: michael@0: this.processMessage({array: array, offset: offset}, options); michael@0: }, michael@0: }; michael@0: michael@0: let debug; michael@0: if (DEBUG) { michael@0: debug = function (s) { michael@0: dump("-*- WapPushManager: " + s + "\n"); michael@0: }; michael@0: } else { michael@0: debug = function (s) {}; michael@0: } michael@0: michael@0: this.EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([ michael@0: "WapPushManager", michael@0: ]); michael@0: