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: let WSP = {}; michael@0: Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP); michael@0: let WBXML = {}; michael@0: Cu.import("resource://gre/modules/WbxmlPduHelper.jsm", WBXML); michael@0: michael@0: // set to true to see debug messages michael@0: let DEBUG = WBXML.DEBUG_ALL | false; michael@0: michael@0: /** michael@0: * Public identifier for SI michael@0: * michael@0: * @see http://technical.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.aspx michael@0: */ michael@0: const PUBLIC_IDENTIFIER_SI = "-//WAPFORUM//DTD SI 1.0//EN"; michael@0: michael@0: /** michael@0: * Parse inline date encoded in OPAQUE format. michael@0: * michael@0: * @param data michael@0: * A wrapped object containing raw PDU data. michael@0: * @param msg michael@0: * Target object for decoding. michael@0: * michael@0: * @see WAP-167-SERVICEIND-20010731-A, clause 8.2.2 michael@0: * michael@0: */ michael@0: this.OpaqueAsDate = { michael@0: decode: function decode_opaque_as_date(data) { michael@0: let size = WSP.UintVar.decode(data); michael@0: let dateBuf = [0, 0, 0, 0, 0, 0, 0]; michael@0: michael@0: // Maximum length for date is 7 bytes. michael@0: if (size > dateBuf.length) michael@0: size = dateBuf.length michael@0: michael@0: // Read date date, non-specified parts remain 0. michael@0: for (let i = 0; i < size; i++) { michael@0: dateBuf[i] = WSP.Octet.decode(data); michael@0: } michael@0: michael@0: // Decode and return result in "YYYY-MM-DDThh:mm:ssZ" form michael@0: let year = ((dateBuf[0] >> 4) & 0x0F) * 1000 + (dateBuf[0] & 0x0F) * 100 + michael@0: ((dateBuf[1] >> 4) & 0x0F) * 10 + (dateBuf[1] & 0x0F); michael@0: let month = ((dateBuf[2] >> 4) & 0x0F) * 10 + (dateBuf[2] & 0x0F); michael@0: let date = ((dateBuf[3] >> 4) & 0x0F) * 10 + (dateBuf[3] & 0x0F); michael@0: let hour = ((dateBuf[4] >> 4) & 0x0F) * 10 + (dateBuf[4] & 0x0F); michael@0: let minute = ((dateBuf[5] >> 4) & 0x0F) * 10 + (dateBuf[5] & 0x0F); michael@0: let second = ((dateBuf[6] >> 4) & 0x0F) * 10 + (dateBuf[6] & 0x0F); michael@0: let dateValue = new Date(Date.UTC(year, month - 1, date, hour, minute, second)); michael@0: michael@0: return dateValue.toISOString().replace(".000", ""); michael@0: }, michael@0: }; michael@0: michael@0: this.PduHelper = { michael@0: michael@0: /** michael@0: * @param data michael@0: * A wrapped object containing raw PDU data. michael@0: * @param contentType michael@0: * Content type of incoming SI message, should be "text/vnd.wap.si" or michael@0: * "application/vnd.wap.sic". michael@0: * michael@0: * @return A message object containing attribute content and contentType. michael@0: * |content| will contain string of decoded SI message if successfully michael@0: * decoded, or raw data if failed. michael@0: * |contentType| will be string representing corresponding type of michael@0: * content. michael@0: */ michael@0: parse: function parse_si(data, contentType) { michael@0: // We only need content and contentType michael@0: let msg = { michael@0: contentType: contentType michael@0: }; michael@0: michael@0: /** michael@0: * Message is compressed by WBXML, decode into string. michael@0: * michael@0: * @see WAP-192-WBXML-20010725-A michael@0: */ michael@0: if (contentType === "application/vnd.wap.sic") { michael@0: let globalTokenOverride = {}; michael@0: globalTokenOverride[0xC3] = { michael@0: number: 0xC3, michael@0: coder: OpaqueAsDate michael@0: }; michael@0: michael@0: let appToken = { michael@0: publicId: PUBLIC_IDENTIFIER_SI, michael@0: tagTokenList: SI_TAG_FIELDS, michael@0: attrTokenList: SI_ATTRIBUTE_FIELDS, michael@0: valueTokenList: SI_VALUE_FIELDS, michael@0: globalTokenOverride: globalTokenOverride michael@0: } michael@0: michael@0: try { michael@0: let parseResult = WBXML.PduHelper.parse(data, appToken); michael@0: msg.content = parseResult.content; michael@0: msg.contentType = "text/vnd.wap.si"; michael@0: } catch (e) { michael@0: // Provide raw data if we failed to parse. michael@0: msg.content = data.array; michael@0: } michael@0: return msg; michael@0: } michael@0: michael@0: /** michael@0: * Message is plain text, transform raw to string. michael@0: */ michael@0: try { michael@0: let stringData = WSP.Octet.decodeMultiple(data, data.array.length); michael@0: msg.content = WSP.PduHelper.decodeStringContent(stringData, "UTF-8"); michael@0: } catch (e) { michael@0: // Provide raw data if we failed to parse. michael@0: msg.content = data.array; michael@0: } michael@0: return msg; michael@0: michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * Tag tokens michael@0: * michael@0: * @see WAP-167-SERVICEIND-20010731-A, clause 8.3.1 michael@0: */ michael@0: const SI_TAG_FIELDS = (function () { michael@0: let names = {}; michael@0: function add(name, codepage, number) { michael@0: let entry = { michael@0: name: name, michael@0: number: number, michael@0: }; michael@0: if (!names[codepage]) { michael@0: names[codepage] = {}; michael@0: } michael@0: names[codepage][number] = entry; michael@0: } michael@0: michael@0: add("si", 0, 0x05); michael@0: add("indication", 0, 0x06); michael@0: add("info", 0, 0x07); michael@0: add("item", 0, 0x08); michael@0: michael@0: return names; michael@0: })(); michael@0: michael@0: /** michael@0: * Attribute Tokens michael@0: * michael@0: * @see WAP-167-SERVICEIND-20010731-A, clause 8.3.2 michael@0: */ michael@0: const SI_ATTRIBUTE_FIELDS = (function () { michael@0: let names = {}; michael@0: function add(name, value, codepage, number) { michael@0: let entry = { michael@0: name: name, michael@0: value: value, michael@0: number: number, michael@0: }; michael@0: if (!names[codepage]) { michael@0: names[codepage] = {}; michael@0: } michael@0: names[codepage][number] = entry; michael@0: } michael@0: michael@0: add("action", "signal-none", 0, 0x05); michael@0: add("action", "signal-low", 0, 0x06); michael@0: add("action", "signal-medium", 0, 0x07); michael@0: add("action", "signal-high", 0, 0x08); michael@0: add("action", "delete", 0, 0x09); michael@0: add("created", "", 0, 0x0A); michael@0: add("href", "", 0, 0x0B); michael@0: add("href", "http://", 0, 0x0C); michael@0: add("href", "http://www.", 0, 0x0D); michael@0: add("href", "https://", 0, 0x0E); michael@0: add("href", "https://www.", 0, 0x0F); michael@0: add("si-expires", "", 0, 0x10); michael@0: add("si-id", "", 0, 0x11); michael@0: add("class", "", 0, 0x12); michael@0: michael@0: return names; michael@0: })(); michael@0: michael@0: const SI_VALUE_FIELDS = (function () { michael@0: let names = {}; michael@0: function add(value, codepage, number) { michael@0: let entry = { michael@0: value: value, michael@0: number: number, michael@0: }; michael@0: if (!names[codepage]) { michael@0: names[codepage] = {}; michael@0: } michael@0: names[codepage][number] = entry; michael@0: } michael@0: michael@0: add(".com/", 0, 0x85); michael@0: add(".edu/", 0, 0x86); michael@0: add(".net/", 0, 0x87); michael@0: add(".org/", 0, 0x88); michael@0: michael@0: return names; michael@0: })(); michael@0: michael@0: this.EXPORTED_SYMBOLS = [ michael@0: // Parser michael@0: "PduHelper", michael@0: ];