/* global Promise, Provisioning, MessageDB */ (function(exports) { 'use strict'; /** * Default constructor, use it to copy objects. To parse objects from XML use * the factory function from() * * @param {Object} [obj] An object from which to copy the fields. */ function ParsedMessage(obj) { if (obj) { for (var key in obj) { this[key] = obj[key]; } } } ParsedMessage.prototype = { /** * Constructor, this is for internal use only */ constructor: ParsedMessage, /** * Creates an untyped object from a typed one * * @return {Object} An untyped representation of this object. */ toJSON: function pm_toJSON() { var obj = { type: this.type, sender: this.sender, serviceId: this.serviceId, timestamp: this.timestamp }; if (this.href) { obj.href = this.href; } if (this.id) { obj.id = this.id; } if (this.created) { obj.created = this.created; } if (this.expires) { obj.expires = this.expires; } if (this.text) { obj.text = this.text; } if (this.action) { obj.action = this.action; } if (this.provisioning) { obj.provisioning = this.provisioning; } return obj; }, /** * Saves the message in the database. Returns a promise that resolves * to a string describing the status of the message: 'new' if the message * was new, 'updated' if the message updated an existing message or * 'discarded' if the message was discarded. * * @return {Object} A promise for this operation. */ save: function pm_save() { var self = this; var json_message = this.toJSON(); return MessageDB.put(json_message).then(function(status) { if (status === 'updated') { // In case the message was updated we must update the original too. self.timestamp = json_message.timestamp; } return Promise.resolve(status); }); }, /** * Returns true if the message has already expired */ isExpired: function pm_isExpired() { return (this.expires && (this.expires < Date.now())) || false; }, /** * Gets the message unique identifier * * @returns {String} An identifier for this message */ getUniqueId: function pm_getUniqueId() { return this.timestamp; } }; /** * Parse a message and returns an object holding its fields. The returned * object will contain the following fields: * - type: the content type of the message, either 'text/vnd.wap.si' or * 'text/vnd.wap.sl' * - sender: the sender of this message, a MSISDN * - timestamp: a timestamp taken when parsing the object * - href: optional for SI messages, required for SL, a URL to be displayed * - id: optional for SI messages, a pseudo-unique ID for the message * - created: optional for SI messages, creation time of this message * - expires: optional for SI messages, expiration time of this message * - action: optional for SI/SL message, action to be executed * - provisioning: only for CP messages, CP related object * - text: optional, text to be displayed * * @param {Object} message A WAP Push message as delivered by the system. * @param {Object} timestamp A timestamp for the message reception time. * * @return {Object} An object holding the contents of the WAP message as * separate fields. */ ParsedMessage.from = function pm_from(message, timestamp) { var parser = new DOMParser(); var doc = parser.parseFromString(message.content, 'text/xml'); var obj = new ParsedMessage(); // We don't check for errors as the message has already been validated obj.type = message.contentType; obj.sender = message.sender; obj.serviceId = message.serviceId; obj.timestamp = timestamp.toString(); if (message.contentType === 'text/vnd.wap.si') { // SI message var indicationNode = doc.querySelector('indication'); // 'href' attribute, optional, string if (indicationNode.hasAttribute('href')) { obj.href = indicationNode.getAttribute('href'); } obj.text = indicationNode.textContent; // 'created' attribute, optional, date in ISO 8601 format if (indicationNode.hasAttribute('created')) { var date = new Date(indicationNode.getAttribute('created')); obj.created = date.getTime(); } // 'si-expires' attribute, optional, date in ISO 8601 format if (indicationNode.hasAttribute('si-expires')) { var expiresDate = new Date(indicationNode.getAttribute('si-expires')); obj.expires = expiresDate.getTime(); } /* 'action' attribute, optional, string, defaults to 'signal-medium' when * not present in the incoming message, see WAP-167 7.2 */ if (indicationNode.hasAttribute('action')) { obj.action = indicationNode.getAttribute('action'); } else { obj.action = 'signal-medium'; } // 'si-id' attribute, optional, string if (indicationNode.hasAttribute('si-id')) { obj.id = indicationNode.getAttribute('si-id'); } else if (obj.action === 'delete') { /* If the message has a 'delete' action but no 'si-id' field than it's * malformed and should be immediately discarded, see WAP-167 6.2 */ return null; } else if (obj.href) { /* If the 'si-id' attribute is not specified then its value is * considered to be the same as the value of the 'href' attribute, * see WAP-167 5.2.1 */ obj.id = obj.href; } } else if (message.contentType === 'text/vnd.wap.sl') { // SL message var slNode = doc.querySelector('sl'); // 'href' attribute, always present obj.href = slNode.getAttribute('href'); /* 'action' attribute, optional, string, defaults to 'execute-low' when * not present in the incoming message, see WAP-168 5.2 */ if (slNode.hasAttribute('action')) { obj.action = slNode.getAttribute('action'); } else { obj.action = 'execute-low'; } } else if (message.contentType === 'text/vnd.wap.connectivity-xml') { // Client provisioning (CP) message obj.provisioning = Provisioning.fromMessage(message); // Security information is mandatory for the application. The application // must discard any message with no security information. if (!obj.provisioning.authInfo) { return null; } var authInfo = obj.provisioning.authInfo; // Let's discard any message that was not successfully authenticated by // gecko. if (authInfo.checked && !authInfo.pass) { return null; } obj.text = 'cp-message-received'; } else { return null; } return obj; }; /** * Loads the message corresponding to the specified timestamp from the * database. Returns a promise that resolves to the message. If the message * is not present the promise will be rejected. * * @param {Number} timestamp The timestamp of the message we want to * retrieve. * * @returns {Object} A promise for this operation. */ ParsedMessage.load = function pm_load(timestamp) { return MessageDB.retrieve(timestamp).then(function(message) { return new ParsedMessage(message); }); }; exports.ParsedMessage = ParsedMessage; })(window);