/* global MessageDB, ParsedProvisioningDoc, ProvisioningAuthentication, StoreProvisioning, WapPushManager, Utils */ /* exported CpScreenHelper */ 'use strict'; var CpScreenHelper = (function() { /** Content provisioning screen node */ var cpScreen = null; /** Pin screen node */ var pinScreen = null; /** APN screen node */ var apnScreen = null; /** Details screen node */ var detailsScreen = null; /** Quit app button node */ var quitButton = null; /** Cancel quit app button node */ var cancelQuitButton = null; /** Accept install configuration button node */ var acceptInstallCfgButton = null; /** Cancel install configuration button node */ var cancelInstallCfgButton = null; /** Finish button node */ var finishButton = null; /** PIN input node */ var pin = null; /** Quit app confirm dialog node */ var quitAppConfirmDialog = null; /** Install configuration confirm dialog node */ var installCfgConfirmDialog = null; /** Auth failure message */ var authFailureMessage = null; /** Help message */ var pinHelp = null; /** Finish confirm dialog node */ var finishConfirmDialog = null; /** User PIN is needed, show input node */ var showPINInput = false; /** The message has not been authenticated yet */ var authenticated = false; /** Flag that holds the result of the authentication process */ var isDocumentValid = false; /** The message has not been processed yet */ var processed = false; /** Message id for notification management */ var messageTag = null; /** Authentication parameter for the WAP PUSH message. */ var authInfo = null; /** WAP provisioning document */ var provisioningDoc = null; /** All APNs list */ var apns = null; /** Index of the card on which the message was received. */ var iccCardIndex = 0; /** Accept button node for each screen */ var acceptApnButton = null; var acceptPinButton = null; var acceptDetailsButton = null; /** Title of the message, usually holds the sender's number */ var titleApn = null; var titleDetails = null; var titlePin = null; /** Flag to define the flow of details screen */ var multipleApns = false; /** Header of details screen */ var headerDetails = null; function cpsh_init() { // Let's consider the message is completely processed once the settings are // stored into the database. processed = false; // Retrieve the various page elements titleApn = document.getElementById('title-apn'); titleDetails = document.getElementById('title-details'); titlePin = document.getElementById('title-pin'); quitAppConfirmDialog = document.getElementById('cp-quit-app-confirm'); quitButton = quitAppConfirmDialog.querySelector('.quit'); cancelQuitButton = quitAppConfirmDialog.querySelector('.cancel'); installCfgConfirmDialog = document.getElementById('cp-install-configuration-confirm'); acceptInstallCfgButton = installCfgConfirmDialog.querySelector('.accept'); cancelInstallCfgButton = installCfgConfirmDialog.querySelector('.cancel'); authFailureMessage = document.getElementById('cp-auth-failure'); pinHelp = document.getElementById('cp-done-help'); finishConfirmDialog = document.getElementById('cp-finish-confirm'); finishButton = finishConfirmDialog.querySelector('button'); cpScreen = document.getElementById('cp-screen'); pinScreen = document.getElementById('cp-pin-screen'); pin = pinScreen.querySelector('input'); apnScreen = document.getElementById('cp-apn-screen'); detailsScreen = document.getElementById('cp-details-screen'); acceptApnButton = document.getElementById('apn-accept'); acceptPinButton = document.getElementById('pin-accept'); acceptDetailsButton = document.getElementById('details-accept'); var headerApnList = document.getElementById('header-apn-list'); headerDetails = document.getElementById('header-details'); var headerPin = document.getElementById('header-pin'); // Event handlers quitButton.addEventListener('click', cpsh_onQuit); cancelQuitButton.addEventListener('click', cpsh_onCancelQuit); finishButton.addEventListener('click', cpsh_onFinish); pin.addEventListener('keyup', cpsh_onPinInput); acceptApnButton.addEventListener('click', cpsh_onApnAccept); acceptPinButton.addEventListener('click', cpsh_onPinAccept); acceptDetailsButton.addEventListener('click', cpsh_onDetailsAccept); headerApnList.addEventListener('action', cpsh_onClose); headerDetails.addEventListener('action', cpsh_closeDetails); headerPin.addEventListener('action', cpsh_closePin); } /** * Hides all the panels. */ function cpsh_hide() { cpScreen.hidden = true; finishConfirmDialog.hidden = true; installCfgConfirmDialog.hidden = true; quitAppConfirmDialog.hidden = true; } /** * Init the application flow showing a warning prompt that asks to the user if * wants to install the configuration information. */ function cpsh_showConfirmInstallationDialog(message) { installCfgConfirmDialog.hidden = false; acceptInstallCfgButton .addEventListener('click',cpsh_onAcceptInstallCfg.bind(null, message)); cancelInstallCfgButton.addEventListener('click', cpsh_onCancelInstallCfg); } /** * Makes the client provisioning screen visible and populate it. */ function cpsh_populateScreen(message) { cpScreen.hidden = false; var title = Utils.prepareMessageTitle(message); navigator.mozL10n.setAttributes(titleApn, title.id, title.args); navigator.mozL10n.setAttributes(titleDetails, title.id, title.args); navigator.mozL10n.setAttributes(titlePin, title.id, title.args); iccCardIndex = message.serviceId; messageTag = message.timestamp; authInfo = message.provisioning.authInfo; provisioningDoc = message.provisioning.provisioningDoc; // Get the number of APNs to show details or the list of them. var parsedProvisioningDoc = ParsedProvisioningDoc.from(provisioningDoc); apns = parsedProvisioningDoc.getApns(); // The provisioning document might not have valid APNs (other ones that // those ones in APPLICATION nodes for the Browsing Enabler and AC for the // Multimedia Messaging System Enabler). In this case we must not continue. if (apns.length === 0) { message = finishConfirmDialog.querySelector('strong'); navigator.mozL10n.setAttributes(message, 'cp-finish-confirm-dialog-message-no-apns'); finishConfirmDialog.hidden = false; return; } // Make the PIN input visible when the authentication mechanism needs a PIN // 0 NETWPIN, there is no need for an user PIN // 1 USERPIN, the authentication mechanism needs a PIN from the user // 1 USERNETWPIN, the authentication mechanism needs a PIN from the user // 1 USERPINMAC, the authentication mechanism needs a PIN from the user showPINInput = (authInfo.sec !== 'NETWPIN'); // 'message.authInfo.checked' property tell us the authentication process // was already performed by gecko authenticated = authInfo.checked; // 'message.authInfo.pass' property tell us the result of the authentication // process when this process was performed by gecko isDocumentValid = authInfo.pass; if (showPINInput) { // If the document has not been authenticated yet and the PIN code is // needed, show some info and the PIN input element to the user. navigator.mozL10n.setAttributes(pinHelp, 'cp-accept-help-pin'); pin.type = 'number'; acceptPinButton.disabled = true; } else { navigator.mozL10n.setAttributes(pinHelp, 'cp-done-help'); pin.type = 'hidden'; pin.blur(); acceptPinButton.disabled = false; } if (apns.length > 1) { multipleApns = true; cpsh_showApnList(); return; } multipleApns = false; cpsh_showDetails(0); } /** * Shows the apn list screen when there are multiple apns in a configuration * message populating a list with each apn name. */ function cpsh_showApnList() { var fragment = document.createDocumentFragment(); for (var i = 0; i < apns.length; i++) { var list = document.createElement('li'); var a = document.createElement('a'); a.addEventListener('click', cpsh_showDetails.bind(null, i)); var aside = document.createElement('aside'); aside.className = 'pack-end'; aside.setAttribute('data-icon', 'forward'); // Icon is for presentation only. aside.setAttribute('aria-hidden', true); var p = document.createElement('p'); p.textContent = apns[i].carrier; a.appendChild(aside); a.appendChild(p); list.appendChild(a); fragment.appendChild(list); } var content = apnScreen.querySelector('.message'); content.innerHTML = ''; content.appendChild(fragment); } /** * Handles the application flow when the user clicks on the 'next' button * from the apn list screen. */ function cpsh_onApnAccept() { if (showPINInput) { pinScreen.addEventListener('transitionend', cpsh_setPinFocus); } apnScreen.classList.add('left'); pinScreen.classList.remove('right'); } /** * Shows the apn details screen. */ function cpsh_showDetails(index) { if (multipleApns) { acceptDetailsButton.style.visibility = 'hidden'; headerDetails.setAttribute('action', 'back'); } var details = detailsScreen.querySelector('.message'); details.innerHTML = ''; cpsh_createNode(details, 'Name', apns[index].carrier); cpsh_createNode(details, 'APN', apns[index].apn); cpsh_createNode(details, 'Proxy', apns[index].proxy); cpsh_createNode(details, 'Port', apns[index].port); cpsh_createNode(details, 'Username', apns[index].user); cpsh_createNode(details, 'Password', apns[index].password); cpsh_createNode(details, 'MMSC', apns[index].mmsc); cpsh_createNode(details, 'MMS Proxy', apns[index].mmsproxy); cpsh_createNode(details, 'MMS Port', apns[index].mmsport); cpsh_createNode(details, 'Authentication Type', apns[index].authType); cpsh_createNode(details, 'APN Type', apns[index].types); detailsScreen.classList.remove('right'); apnScreen.classList.add('left'); } /** * Handles the application flow when the user clicks on the 'back'/ 'close' * button from the details screen. * If there are multiple APNs then back button to go back to apn list screen. * If only one APN then shows quit confirm. */ function cpsh_closeDetails(evt) { if (!multipleApns) { cpsh_onClose(evt); return; } detailsScreen.classList.add('right'); apnScreen.classList.remove('left'); } /** * Handles the application flow when the user clicks on the 'next' button * from the details screen. */ function cpsh_onDetailsAccept() { if (showPINInput) { pinScreen.addEventListener('transitionend', cpsh_setPinFocus); } detailsScreen.classList.add('left'); pinScreen.classList.remove('right'); } /** * Helper function used to populate the list of the APN details. */ function cpsh_createNode(rootNode, key, value) { if (!value) { return; } var element = document.createElement('li'); var nodeKey = document.createElement('p'); var nodeValue = document.createElement('p'); nodeKey.textContent = key; nodeValue.textContent = value; element.appendChild(nodeKey); element.appendChild(nodeValue); rootNode.appendChild(element); } /** * Helper function used to set focus to pin input when transition to pin * screen has finished. */ function cpsh_setPinFocus() { pin.focus(); pinScreen.removeEventListener('transitionend', cpsh_setPinFocus); } /** * Handles the application flow when the user clicks on the 'back' button * from the pin screen. */ function cpsh_closePin() { pin.blur(); if (!multipleApns) { pinScreen.classList.add('right'); detailsScreen.classList.remove('left'); return; } pinScreen.classList.add('right'); apnScreen.classList.remove('left'); } /** * Handles the application flow when the user clicks on the 'close' button * from the client provisioning screen. */ function cpsh_onClose(evt) { if (processed) { WapPushManager.close(); return; } quitAppConfirmDialog.hidden = false; } /** * Handles the application flow when the user clicks on the 'Quit' button * from the client provisioning quit app confirm dialog. */ function cpsh_onQuit(evt) { evt.preventDefault(); MessageDB.deleteByTimestamp(messageTag).then(function() { WapPushManager.close(); }, function() { console.error('Could not delete message from the database'); WapPushManager.close(); }); } /** * Handles the application flow when the user clicks on the 'Cancel' button * from the client provisioning quit app confirm dialog. */ function cpsh_onCancelQuit(evt) { evt.preventDefault(); quitAppConfirmDialog.hidden = true; } /** * Handles the application flow when the user clicks on the 'Cancel' button * from the client install configuration screen. */ function cpsh_onCancelInstallCfg(evt) { evt.preventDefault(); WapPushManager.close(); } /** * Handles the application flow when the user clicks on the 'Cancel' button * from the client install configuration screen. */ function cpsh_onAcceptInstallCfg(message, evt) { evt.preventDefault(); cpsh_populateScreen(message); installCfgConfirmDialog.hidden = true; } /** * Accepts the message, authenticates the sender and presents the settings to * be stored to the user */ function cpsh_onPinAccept() { var message = null; if (!authenticated) { if (!pin.value) { // Need a valid PIN code, show error. cpsh_pinError(); return; } try { // Need to perform the authentication process. isDocumentValid = ProvisioningAuthentication.isDocumentValid(pin.value, authInfo); } catch (e) { message = finishConfirmDialog.querySelector('strong'); navigator.mozL10n.setAttributes(message, e.message); finishConfirmDialog.hidden = false; return; } authenticated = true; if (!isDocumentValid) { // The document couldn't be authenticated, show error. authenticated = false; cpsh_pinError(); return; } } processed = true; // Store APNs into the database. StoreProvisioning.provision(apns, iccCardIndex); /* Show finish confirm dialog after having deleted the message, this is * done even if the deletion fails for some reason. */ MessageDB.deleteByTimestamp(messageTag).then(function() { finishConfirmDialog.hidden = false; }, function(e) { console.error('Could not delete message from the database: ', e); finishConfirmDialog.hidden = false; }); } function cpsh_pinError() { authFailureMessage.hidden = false; pinHelp.hidden = true; pin.focus(); // Set max to -1 in order to show invalid input. pin.setAttribute('max', -1); pin.addEventListener('keyup', cpsh_onPinErrorRestore); } function cpsh_onPinErrorRestore() { authFailureMessage.hidden = true; pinHelp.hidden = false; pin.removeAttribute('max'); pin.addEventListener('keyup', cpsh_onPinInput); } /** * Handles the application flow when the user clicks on the 'Finish' button * from the client provisioning finish confirm dialog. */ function cpsh_onFinish(evt) { evt.preventDefault(); WapPushManager.close(); } /** * Enable / disable accept button if pin field is empty. */ function cpsh_onPinInput(evt) { acceptPinButton.disabled = (pin.value.length === 0); } return { init: cpsh_init, hide: cpsh_hide, showConfirmInstallationDialog: cpsh_showConfirmInstallationDialog }; })();