From dd5f4ce90a8176e6884a4df3e9a0a8dfc108425c Mon Sep 17 00:00:00 2001 From: Vicamo Yang Date: Wed, 4 Sep 2013 15:53:50 +0800 Subject: [PATCH] Bug 873351 - B2G SMS: move SMS code out of RadioInterfaceLayer to SmsService. r=gene --- b2g/installer/package-manifest.in | 2 + browser/installer/package-manifest.in | 2 + dom/mobilemessage/interfaces/moz.build | 1 + .../interfaces/nsIRilSmsService.idl | 11 + .../interfaces/nsISmsService.idl | 3 +- dom/mobilemessage/src/Makefile.in | 6 - dom/mobilemessage/src/SmsServicesFactory.cpp | 13 +- dom/mobilemessage/src/android/SmsService.cpp | 8 - dom/mobilemessage/src/fallback/SmsService.cpp | 8 - dom/mobilemessage/src/gonk/SmsService.cpp | 85 -- dom/mobilemessage/src/gonk/SmsService.h | 35 - dom/mobilemessage/src/gonk/SmsService.js | 994 ++++++++++++++++++ .../src/gonk/SmsService.manifest | 3 + dom/mobilemessage/src/ipc/SmsIPCService.cpp | 8 - dom/mobilemessage/src/moz.build | 4 +- dom/system/gonk/RadioInterfaceLayer.js | 841 +-------------- dom/system/gonk/nsIRadioInterfaceLayer.idl | 14 +- 17 files changed, 1032 insertions(+), 1006 deletions(-) create mode 100644 dom/mobilemessage/interfaces/nsIRilSmsService.idl delete mode 100644 dom/mobilemessage/src/gonk/SmsService.cpp delete mode 100644 dom/mobilemessage/src/gonk/SmsService.h create mode 100644 dom/mobilemessage/src/gonk/SmsService.js create mode 100644 dom/mobilemessage/src/gonk/SmsService.manifest diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index f358d9f1007d..e0e660cdbc58 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -460,6 +460,8 @@ @BINPATH@/components/RadioInterfaceLayer.js @BINPATH@/components/MmsService.manifest @BINPATH@/components/MmsService.js +@BINPATH@/components/SmsService.manifest +@BINPATH@/components/SmsService.js @BINPATH@/components/RILContentHelper.js @BINPATH@/components/MobileMessageDatabaseService.manifest @BINPATH@/components/MobileMessageDatabaseService.js diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 387a7915c873..71b851364de3 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -446,6 +446,8 @@ @BINPATH@/components/RadioInterfaceLayer.js @BINPATH@/components/MmsService.manifest @BINPATH@/components/MmsService.js +@BINPATH@/components/SmsService.manifest +@BINPATH@/components/SmsService.js @BINPATH@/components/RILContentHelper.js @BINPATH@/components/MobileMessageDatabaseService.manifest @BINPATH@/components/MobileMessageDatabaseService.js diff --git a/dom/mobilemessage/interfaces/moz.build b/dom/mobilemessage/interfaces/moz.build index 52cc79b9288c..dd41f43b7761 100644 --- a/dom/mobilemessage/interfaces/moz.build +++ b/dom/mobilemessage/interfaces/moz.build @@ -25,6 +25,7 @@ XPIDL_SOURCES += [ if CONFIG['MOZ_B2G_RIL']: XPIDL_SOURCES += [ 'nsIRilMobileMessageDatabaseService.idl', + 'nsIRilSmsService.idl', ] XPIDL_MODULE = 'dom_mobilemessage' diff --git a/dom/mobilemessage/interfaces/nsIRilSmsService.idl b/dom/mobilemessage/interfaces/nsIRilSmsService.idl new file mode 100644 index 000000000000..ef2e853d8a5e --- /dev/null +++ b/dom/mobilemessage/interfaces/nsIRilSmsService.idl @@ -0,0 +1,11 @@ +/* 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 "nsISmsService.idl" + +[scriptable, uuid(f216903c-bdf5-4988-b894-f62fd91df114)] +interface nsIRilSmsService : nsISmsService +{ + void notifyMessageReceived(in jsval message); +}; diff --git a/dom/mobilemessage/interfaces/nsISmsService.idl b/dom/mobilemessage/interfaces/nsISmsService.idl index 0623d62ef78f..2250e46a2e19 100644 --- a/dom/mobilemessage/interfaces/nsISmsService.idl +++ b/dom/mobilemessage/interfaces/nsISmsService.idl @@ -13,7 +13,7 @@ interface nsIMobileMessageCallback; #define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1" %} -[scriptable, builtinclass, uuid(f0d5d11b-0326-4cb1-bb76-a3f912212287)] +[scriptable, uuid(7ef8e361-9db6-46ed-badc-2901e1049e5d)] interface nsISmsService : nsISupports { boolean hasSupport(); @@ -25,7 +25,6 @@ interface nsISmsService : nsISupports in boolean silent, in nsIMobileMessageCallback request); - boolean isSilentNumber(in DOMString number); void addSilentNumber(in DOMString number); void removeSilentNumber(in DOMString number); }; diff --git a/dom/mobilemessage/src/Makefile.in b/dom/mobilemessage/src/Makefile.in index e45e9b971def..ae94f960a3cf 100644 --- a/dom/mobilemessage/src/Makefile.in +++ b/dom/mobilemessage/src/Makefile.in @@ -31,11 +31,5 @@ LOCAL_INCLUDES = \ # subdirectory (and the ipc one). LOCAL_INCLUDES += $(VPATH:%=-I%) -ifdef MOZ_B2G_RIL -LOCAL_INCLUDES += \ - -I$(topsrcdir)/dom/system/gonk \ - $(NULL) -endif - include $(topsrcdir)/config/rules.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk diff --git a/dom/mobilemessage/src/SmsServicesFactory.cpp b/dom/mobilemessage/src/SmsServicesFactory.cpp index efcf0171834b..94ffef77b929 100644 --- a/dom/mobilemessage/src/SmsServicesFactory.cpp +++ b/dom/mobilemessage/src/SmsServicesFactory.cpp @@ -5,16 +5,18 @@ #include "SmsServicesFactory.h" #include "nsXULAppAPI.h" -#include "SmsService.h" #include "SmsIPCService.h" #ifndef MOZ_B2G_RIL #include "MobileMessageDatabaseService.h" #include "MmsService.h" +#include "SmsService.h" #endif #include "nsServiceManagerUtils.h" #define RIL_MMSSERVICE_CONTRACTID "@mozilla.org/mms/rilmmsservice;1" -#define RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1" +#define RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID \ + "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1" +#define RIL_SMSSERVICE_CONTRACTID "@mozilla.org/sms/rilsmsservice;1" namespace mozilla { namespace dom { @@ -28,7 +30,11 @@ SmsServicesFactory::CreateSmsService() if (XRE_GetProcessType() == GeckoProcessType_Content) { smsService = new SmsIPCService(); } else { +#ifdef MOZ_B2G_RIL + smsService = do_GetService(RIL_SMSSERVICE_CONTRACTID); +#else smsService = new SmsService(); +#endif } return smsService.forget(); @@ -42,7 +48,8 @@ SmsServicesFactory::CreateMobileMessageDatabaseService() mobileMessageDBService = new SmsIPCService(); } else { #ifdef MOZ_B2G_RIL - mobileMessageDBService = do_GetService(RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); + mobileMessageDBService = + do_GetService(RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); #else mobileMessageDBService = new MobileMessageDatabaseService(); #endif diff --git a/dom/mobilemessage/src/android/SmsService.cpp b/dom/mobilemessage/src/android/SmsService.cpp index 146190766fac..c5a67319984e 100644 --- a/dom/mobilemessage/src/android/SmsService.cpp +++ b/dom/mobilemessage/src/android/SmsService.cpp @@ -53,14 +53,6 @@ SmsService::Send(const nsAString& aNumber, return NS_OK; } -NS_IMETHODIMP -SmsService::IsSilentNumber(const nsAString& aNumber, - bool* aIsSilent) -{ - NS_NOTYETIMPLEMENTED("Implement me!"); - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMETHODIMP SmsService::AddSilentNumber(const nsAString& aNumber) { diff --git a/dom/mobilemessage/src/fallback/SmsService.cpp b/dom/mobilemessage/src/fallback/SmsService.cpp index 5df3504226b1..430edab6f15c 100644 --- a/dom/mobilemessage/src/fallback/SmsService.cpp +++ b/dom/mobilemessage/src/fallback/SmsService.cpp @@ -39,14 +39,6 @@ SmsService::Send(const nsAString& aNumber, return NS_ERROR_FAILURE; } -NS_IMETHODIMP -SmsService::IsSilentNumber(const nsAString& aNumber, - bool* aIsSilent) -{ - NS_ERROR("We should not be here!"); - return NS_ERROR_FAILURE; -} - NS_IMETHODIMP SmsService::AddSilentNumber(const nsAString& aNumber) { diff --git a/dom/mobilemessage/src/gonk/SmsService.cpp b/dom/mobilemessage/src/gonk/SmsService.cpp deleted file mode 100644 index 484dd94091aa..000000000000 --- a/dom/mobilemessage/src/gonk/SmsService.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "SmsMessage.h" -#include "SmsService.h" -#include "jsapi.h" -#include "SmsSegmentInfo.h" - -namespace mozilla { -namespace dom { -namespace mobilemessage { - -NS_IMPL_ISUPPORTS1(SmsService, nsISmsService) - -SmsService::SmsService() -{ - nsCOMPtr ril = do_GetService("@mozilla.org/ril;1"); - if (ril) { - ril->GetRadioInterface(0, getter_AddRefs(mRadioInterface)); - } - NS_WARN_IF_FALSE(mRadioInterface, "This shouldn't fail!"); -} - -NS_IMETHODIMP -SmsService::HasSupport(bool* aHasSupport) -{ - *aHasSupport = true; - return NS_OK; -} - -NS_IMETHODIMP -SmsService::GetSegmentInfoForText(const nsAString & aText, - nsIDOMMozSmsSegmentInfo** aResult) -{ - NS_ENSURE_TRUE(mRadioInterface, NS_ERROR_FAILURE); - - return mRadioInterface->GetSegmentInfoForText(aText, aResult); -} - -NS_IMETHODIMP -SmsService::Send(const nsAString& aNumber, - const nsAString& aMessage, - const bool aSilent, - nsIMobileMessageCallback* aRequest) -{ - NS_ENSURE_TRUE(mRadioInterface, NS_ERROR_FAILURE); - - return mRadioInterface->SendSMS(aNumber, aMessage, aSilent, aRequest); -} - -NS_IMETHODIMP -SmsService::IsSilentNumber(const nsAString& aNumber, - bool* aIsSilent) -{ - *aIsSilent = mSilentNumbers.Contains(aNumber); - return NS_OK; -} - -NS_IMETHODIMP -SmsService::AddSilentNumber(const nsAString& aNumber) -{ - if (mSilentNumbers.Contains(aNumber)) { - return NS_ERROR_UNEXPECTED; - } - - NS_ENSURE_TRUE(mSilentNumbers.AppendElement(aNumber), NS_ERROR_FAILURE); - return NS_OK; -} - -NS_IMETHODIMP -SmsService::RemoveSilentNumber(const nsAString& aNumber) -{ - if (!mSilentNumbers.Contains(aNumber)) { - return NS_ERROR_INVALID_ARG; - } - - NS_ENSURE_TRUE(mSilentNumbers.RemoveElement(aNumber), NS_ERROR_FAILURE); - return NS_OK; -} - -} // namespace mobilemessage -} // namespace dom -} // namespace mozilla diff --git a/dom/mobilemessage/src/gonk/SmsService.h b/dom/mobilemessage/src/gonk/SmsService.h deleted file mode 100644 index 940cbf2fa816..000000000000 --- a/dom/mobilemessage/src/gonk/SmsService.h +++ /dev/null @@ -1,35 +0,0 @@ -/* 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/. */ - -#ifndef mozilla_dom_mobilemessage_SmsService_h -#define mozilla_dom_mobilemessage_SmsService_h - -#include "nsISmsService.h" -#include "nsCOMPtr.h" -#include "nsIRadioInterfaceLayer.h" -#include "nsTArray.h" -#include "nsString.h" - -namespace mozilla { -namespace dom { -namespace mobilemessage { - -class SmsService : public nsISmsService -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSISMSSERVICE - SmsService(); - -protected: - // TODO: Bug 854326 - B2G Multi-SIM: support multiple SIM cards for SMS/MMS - nsCOMPtr mRadioInterface; - nsTArray mSilentNumbers; -}; - -} // namespace mobilemessage -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_mobilemessage_SmsService_h diff --git a/dom/mobilemessage/src/gonk/SmsService.js b/dom/mobilemessage/src/gonk/SmsService.js new file mode 100644 index 000000000000..853b66e04b9b --- /dev/null +++ b/dom/mobilemessage/src/gonk/SmsService.js @@ -0,0 +1,994 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 et filetype=javascript + * 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"); + +var RIL = {}; +Cu.import("resource://gre/modules/ril_consts.js", RIL); + +const RIL_SMSSERVICE_CONTRACTID = "@mozilla.org/sms/rilsmsservice;1"; +const RIL_SMSSERVICE_CID = + Components.ID("{46a9ed78-3574-40a1-9f12-ea179942d67f}"); + +const DELIVERY_STATE_RECEIVED = "received"; +const DELIVERY_STATE_SENDING = "sending"; +const DELIVERY_STATE_SENT = "sent"; +const DELIVERY_STATE_ERROR = "error"; + +// Observer topics to send. +const kSmsReceivedObserverTopic = "sms-received"; +const kSmsSendingObserverTopic = "sms-sending"; +const kSmsSentObserverTopic = "sms-sent"; +const kSmsFailedObserverTopic = "sms-failed"; +const kSmsDeliverySuccessObserverTopic = "sms-delivery-success"; +const kSmsDeliveryErrorObserverTopic = "sms-delivery-error"; +const kSilentSmsReceivedObserverTopic = "silent-sms-received"; + +// Observer topics to watch. +const kPrefenceChangedObserverTopic = "nsPref:changed"; +const kXpcomShutdownObserverTopic = "xpcom-shutdown"; + +// Preference keys. +const kPrefKeyRilDebuggingEnabled = "ril.debugging.enabled"; + +XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService", + "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1", + "nsIRilMobileMessageDatabaseService"); + +XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService", + "@mozilla.org/mobilemessage/mobilemessageservice;1", + "nsIMobileMessageService"); + +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", + "@mozilla.org/system-message-internal;1", + "nsISystemMessagesInternal"); + +XPCOMUtils.defineLazyGetter(this, "gRadioInterface", function () { + let ril = Cc["@mozilla.org/ril;1"].getService(Ci["nsIRadioInterfaceLayer"]); + // TODO: Bug 854326 - B2G Multi-SIM: support multiple SIM cards for SMS/MMS + return ril.getRadioInterface(0); +}); + +XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function () { + let ns = {}; + Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns); + return ns.PhoneNumberUtils; +}); + +XPCOMUtils.defineLazyGetter(this, "WAP", function () { + let WAP = {}; + Cu.import("resource://gre/modules/WapPushManager.js", WAP); + return WAP; +}); + +XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () { + let ns = {}; + Cu.import("resource://gre/modules/RilMessageManager.jsm", ns); + return ns.RilMessageManager; +}); + +let DEBUG; +function debug(s) { + dump("SmsService: " + s + "\n"); +} + +/** + * SmsService + */ +function SmsService() { + // Update |DEBUG|. + this.observe(null, kPrefenceChangedObserverTopic, + kPrefKeyRilDebuggingEnabled); + + this.silentNumbers = []; + + this.portAddressedSmsApps = {}; + this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = + this._handleSmsWdpPortPush.bind(this); + + Services.obs.addObserver(this, kPrefenceChangedObserverTopic, false); + Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false); +} +SmsService.prototype = { + + classID: RIL_SMSSERVICE_CID, + classInfo: XPCOMUtils.generateCI({classID: RIL_SMSSERVICE_CID, + contractID: RIL_SMSSERVICE_CONTRACTID, + classDescription: "SmsService", + interfaces: [Ci.nsIRilSmsService, + Ci.nsISmsService], + flags: Ci.nsIClassInfo.SINGLETON}), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsIRilSmsService, + Ci.nsISmsService]), + + /** + * List of tuples of national language identifier pairs. + * + * TODO: Support static/runtime settings, see bug 733331. + */ + enabledGsmTableTuples: [ + [RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT], + ], + + /** + * Use 16-bit reference number for concatenated outgoint messages. + * + * TODO: Support static/runtime settings, see bug 733331. + */ + segmentRef16Bit: false, + + /** + * Get valid SMS concatenation reference number. + */ + segmentRef: 0, + get nextSegmentRef() { + let ref = this.segmentRef++; + + this.segmentRef %= (this.segmentRef16Bit ? 65535 : 255); + + // 0 is not a valid SMS concatenation reference number. + return ref + 1; + }, + + statusReportPendingMessageIds: null, + + portAddressedSmsApps: null, + + silentNumbers: null, + + _getStrict7BitEncoding: function _getStrict7BitEncoding() { + try { + return Services.prefs.getBoolPref("dom.sms.strict7BitEncoding"); + } catch (e) { + return false; + } + }, + + _getRequestStatusReport: function _getRequestStatusReport() { + try { + return Services.prefs.getBoolPref("dom.sms.requestStatusReport"); + } catch (e) { + return true; + } + }, + + _getMsisdn: function _getMsisdn() { + let iccInfo = gRadioInterface.rilContext.iccInfo; + let number = iccInfo ? iccInfo.msisdn : null; + + // Workaround an xpconnect issue with undefined string objects. + // See bug 808220 + if (number === undefined || number === "undefined") { + return null; + } + return number; + }, + + /** + * Calculate encoded length using specified locking/single shift table + * + * @param message + * message string to be encoded. + * @param langTable + * locking shift table string. + * @param langShiftTable + * single shift table string. + * @param strict7BitEncoding + * Optional. Enable Latin characters replacement with corresponding + * ones in GSM SMS 7-bit default alphabet. + * + * @return encoded length in septets. + * + * @note that the algorithm used in this function must match exactly with + * GsmPDUHelper#writeStringAsSeptets. + */ + _countGsm7BitSeptets: function _countGsm7BitSeptets(message, + langTable, + langShiftTable, + strict7BitEncoding) { + let length = 0; + for (let msgIndex = 0; msgIndex < message.length; msgIndex++) { + let c = message.charAt(msgIndex); + if (strict7BitEncoding) { + c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c; + } + + let septet = langTable.indexOf(c); + + // According to 3GPP TS 23.038, section 6.1.1 General notes, "The + // characters marked '1)' are not used but are displayed as a space." + if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) { + continue; + } + + if (septet >= 0) { + length++; + continue; + } + + septet = langShiftTable.indexOf(c); + if (septet < 0) { + if (!strict7BitEncoding) { + return -1; + } + + // Bug 816082, when strict7BitEncoding is enabled, we should replace + // characters that can't be encoded with GSM 7-Bit alphabets with '*'. + c = '*'; + if (langTable.indexOf(c) >= 0) { + length++; + } else if (langShiftTable.indexOf(c) >= 0) { + length += 2; + } else { + // We can't even encode a '*' character with current configuration. + return -1; + } + + continue; + } + + // According to 3GPP TS 23.038 B.2, "This code represents a control + // character and therefore must not be used for language specific + // characters." + if (septet == RIL.PDU_NL_RESERVED_CONTROL) { + continue; + } + + // The character is not found in locking shfit table, but could be + // encoded as with single shift table. Note that it's + // still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE, + // but we can display it as a space in this case as said in previous + // comment. + length += 2; + } + + return length; + }, + + /** + * Calculate user data length of specified message string encoded in GSM 7Bit + * alphabets. + * + * @param message + * a message string to be encoded. + * @param strict7BitEncoding + * Optional. Enable Latin characters replacement with corresponding + * ones in GSM SMS 7-bit default alphabet. + * + * @return null or an options object with attributes `dcs`, + * `userDataHeaderLength`, `encodedFullBodyLength`, `langIndex`, + * `langShiftIndex`, `segmentMaxSeq` set. + * + * @see #_calculateUserDataLength(). + */ + _calculateUserDataLength7Bit: function _calculateUserDataLength7Bit(message, + strict7BitEncoding) { + let options = null; + let minUserDataSeptets = Number.MAX_VALUE; + for (let i = 0; i < this.enabledGsmTableTuples.length; i++) { + let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i]; + + const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; + const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; + + let bodySeptets = this._countGsm7BitSeptets(message, + langTable, + langShiftTable, + strict7BitEncoding); + if (bodySeptets < 0) { + continue; + } + + let headerLen = 0; + if (langIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) { + headerLen += 3; // IEI + len + langIndex + } + if (langShiftIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) { + headerLen += 3; // IEI + len + langShiftIndex + } + + // Calculate full user data length, note the extra byte is for header len + let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7); + let segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT; + if ((bodySeptets + headerSeptets) > segmentSeptets) { + headerLen += this.segmentRef16Bit ? 6 : 5; + headerSeptets = Math.ceil((headerLen + 1) * 8 / 7); + segmentSeptets -= headerSeptets; + } + + let segments = Math.ceil(bodySeptets / segmentSeptets); + let userDataSeptets = bodySeptets + headerSeptets * segments; + if (userDataSeptets >= minUserDataSeptets) { + continue; + } + + minUserDataSeptets = userDataSeptets; + + options = { + dcs: RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET, + encodedFullBodyLength: bodySeptets, + userDataHeaderLength: headerLen, + langIndex: langIndex, + langShiftIndex: langShiftIndex, + segmentMaxSeq: segments, + segmentChars: segmentSeptets, + }; + } + + return options; + }, + + /** + * Calculate user data length of specified message string encoded in UCS2. + * + * @param message + * a message string to be encoded. + * + * @return an options object with attributes `dcs`, `userDataHeaderLength`, + * `encodedFullBodyLength`, `segmentMaxSeq` set. + * + * @see #_calculateUserDataLength(). + */ + _calculateUserDataLengthUCS2: function _calculateUserDataLengthUCS2(message) { + let bodyChars = message.length; + let headerLen = 0; + let headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2); + let segmentChars = RIL.PDU_MAX_USER_DATA_UCS2; + if ((bodyChars + headerChars) > segmentChars) { + headerLen += this.segmentRef16Bit ? 6 : 5; + headerChars = Math.ceil((headerLen + 1) / 2); + segmentChars -= headerChars; + } + + let segments = Math.ceil(bodyChars / segmentChars); + + return { + dcs: RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET, + encodedFullBodyLength: bodyChars * 2, + userDataHeaderLength: headerLen, + segmentMaxSeq: segments, + segmentChars: segmentChars, + }; + }, + + /** + * Calculate user data length and its encoding. + * + * @param message + * a message string to be encoded. + * @param strict7BitEncoding + * Optional. Enable Latin characters replacement with corresponding + * ones in GSM SMS 7-bit default alphabet. + * + * @return an options object with some or all of following attributes set: + * + * @param dcs + * Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET + * constants. + * @param userDataHeaderLength + * Length of embedded user data header, in bytes. The whole header + * size will be userDataHeaderLength + 1; 0 for no header. + * @param encodedFullBodyLength + * Length of the message body when encoded with the given DCS. For + * UCS2, in bytes; for 7-bit, in septets. + * @param langIndex + * Table index used for normal 7-bit encoded character lookup. + * @param langShiftIndex + * Table index used for escaped 7-bit encoded character lookup. + * @param segmentMaxSeq + * Max sequence number of a multi-part messages, or 1 for single one. + * This number might not be accurate for a multi-part message until + * it's processed by #_fragmentText() again. + */ + _calculateUserDataLength: function _calculateUserDataLength(message, + strict7BitEncoding) { + let options = this._calculateUserDataLength7Bit(message, strict7BitEncoding); + if (!options) { + options = this._calculateUserDataLengthUCS2(message); + } + + if (DEBUG) debug("_calculateUserDataLength: " + JSON.stringify(options)); + return options; + }, + + /** + * Fragment GSM 7-Bit encodable string for transmission. + * + * @param text + * text string to be fragmented. + * @param langTable + * locking shift table string. + * @param langShiftTable + * single shift table string. + * @param segmentSeptets + * Number of available spetets per segment. + * @param strict7BitEncoding + * Optional. Enable Latin characters replacement with corresponding + * ones in GSM SMS 7-bit default alphabet. + * + * @return an array of objects. See #_fragmentText() for detailed definition. + */ + _fragmentText7Bit: function _fragmentText7Bit(text, langTable, langShiftTable, + segmentSeptets, + strict7BitEncoding) { + let ret = []; + let body = "", len = 0; + for (let i = 0, inc = 0; i < text.length; i++) { + let c = text.charAt(i); + if (strict7BitEncoding) { + c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c; + } + + let septet = langTable.indexOf(c); + if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) { + continue; + } + + if (septet >= 0) { + inc = 1; + } else { + septet = langShiftTable.indexOf(c); + if (septet == RIL.PDU_NL_RESERVED_CONTROL) { + continue; + } + + inc = 2; + if (septet < 0) { + if (!strict7BitEncoding) { + throw new Error("Given text cannot be encoded with GSM 7-bit Alphabet!"); + } + + // Bug 816082, when strict7BitEncoding is enabled, we should replace + // characters that can't be encoded with GSM 7-Bit alphabets with '*'. + c = '*'; + if (langTable.indexOf(c) >= 0) { + inc = 1; + } + } + } + + if ((len + inc) > segmentSeptets) { + ret.push({ + body: body, + encodedBodyLength: len, + }); + body = c; + len = inc; + } else { + body += c; + len += inc; + } + } + + if (len) { + ret.push({ + body: body, + encodedBodyLength: len, + }); + } + + return ret; + }, + + /** + * Fragment UCS2 encodable string for transmission. + * + * @param text + * text string to be fragmented. + * @param segmentChars + * Number of available characters per segment. + * + * @return an array of objects. See #_fragmentText() for detailed definition. + */ + _fragmentTextUCS2: function _fragmentTextUCS2(text, segmentChars) { + let ret = []; + for (let offset = 0; offset < text.length; offset += segmentChars) { + let str = text.substr(offset, segmentChars); + ret.push({ + body: str, + encodedBodyLength: str.length * 2, + }); + } + + return ret; + }, + + /** + * Fragment string for transmission. + * + * Fragment input text string into an array of objects that contains + * attributes `body`, substring for this segment, `encodedBodyLength`, + * length of the encoded segment body in septets. + * + * @param text + * Text string to be fragmented. + * @param options + * Optional pre-calculated option object. The output array will be + * stored at options.segments if there are multiple segments. + * @param strict7BitEncoding + * Optional. Enable Latin characters replacement with corresponding + * ones in GSM SMS 7-bit default alphabet. + * + * @return Populated options object. + */ + _fragmentText: function _fragmentText(text, options, strict7BitEncoding) { + if (!options) { + options = this._calculateUserDataLength(text, strict7BitEncoding); + } + + if (options.dcs == RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET) { + const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[options.langIndex]; + const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[options.langShiftIndex]; + options.segments = this._fragmentText7Bit(text, + langTable, langShiftTable, + options.segmentChars, + strict7BitEncoding); + } else { + options.segments = this._fragmentTextUCS2(text, + options.segmentChars); + } + + // Re-sync options.segmentMaxSeq with actual length of returning array. + options.segmentMaxSeq = options.segments.length; + + return options; + }, + + /** + * A helper to broadcast the system message to launch registered apps + * like Costcontrol, Notification and Message app... etc. + * + * @param aName + * The system message name. + * @param aDomMessage + * The nsIDOMMozSmsMessage object. + */ + _broadcastSystemMessage: function _broadcastSystemMessage(aName, aDomMessage) { + if (DEBUG) debug("Broadcasting the SMS system message: " + aName); + + // Sadly we cannot directly broadcast the aDomMessage object + // because the system message mechamism will rewrap the object + // based on the content window, which needs to know the properties. + gSystemMessenger.broadcastMessage(aName, { + type: aDomMessage.type, + id: aDomMessage.id, + threadId: aDomMessage.threadId, + delivery: aDomMessage.delivery, + deliveryStatus: aDomMessage.deliveryStatus, + sender: aDomMessage.sender, + receiver: aDomMessage.receiver, + body: aDomMessage.body, + messageClass: aDomMessage.messageClass, + timestamp: aDomMessage.timestamp, + read: aDomMessage.read + }); + }, + + /** + * Handle WDP port push PDU. Constructor WDP bearer information and deliver + * to WapPushManager. + * + * @param message + * A SMS message. + */ + _handleSmsWdpPortPush: function _handleSmsWdpPortPush(message) { + if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) { + if (DEBUG) { + debug("Got port addressed SMS but not encoded in 8-bit alphabet." + + " Drop!"); + } + return; + } + + let options = { + bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN, + sourceAddress: message.sender, + sourcePort: message.header.originatorPort, + destinationAddress: this.rilContext.iccInfo.msisdn, + destinationPort: message.header.destinationPort, + }; + WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length, + 0, options); + }, + + _isSilentNumber: function _isSilentNumber(number) { + return this.silentNumbers.indexOf(number) >= 0; + }, + + /** + * nsISmsService methods. + */ + + // TODO: Bug 859616 - WebSMS: return undefined if the API is unsupported on + // the platform, not null + hasSupport: function hasSupport() { + return true; + }, + + getSegmentInfoForText: function getSegmentInfoForText(text) { + let strict7BitEncoding = this._getStrict7BitEncoding(); + + let options = this._fragmentText(text, null, strict7BitEncoding); + let charsInLastSegment; + if (options.segmentMaxSeq) { + let lastSegment = options.segments[options.segmentMaxSeq - 1]; + charsInLastSegment = lastSegment.encodedBodyLength; + if (options.dcs == RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET) { + // In UCS2 encoding, encodedBodyLength is in octets. + charsInLastSegment /= 2; + } + } else { + charsInLastSegment = 0; + } + + let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq, + options.segmentChars, + options.segmentChars - charsInLastSegment); + return result; + }, + + send: function send(number, message, silent, request) { + let strict7BitEncoding = this._getStrict7BitEncoding(); + let requestStatusReport = this._getRequestStatusReport(); + + let options = this._fragmentText(message, null, strict7BitEncoding); + options.number = gPhoneNumberUtils.normalize(number); + options.requestStatusReport = requestStatusReport && !silent; + if (options.segmentMaxSeq > 1) { + options.segmentRef16Bit = this.segmentRef16Bit; + options.segmentRef = this.nextSegmentRef; + } + + let notifyResult = (function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + if (!silent) { + Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null); + } + + // If the radio is disabled or the SIM card is not ready, just directly + // return with the corresponding error code. + let errorCode; + if (!gPhoneNumberUtils.isPlainPhoneNumber(options.number)) { + if (DEBUG) debug("Error! Address is invalid when sending SMS: " + + options.number); + errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR; + } else if (gRadioInterface.rilContext.radioState != + RIL.GECKO_RADIOSTATE_READY) { + if (DEBUG) debug("Error! Radio is disabled when sending SMS."); + errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR; + } else if (gRadioInterface.rilContext.cardState != + RIL.GECKO_CARDSTATE_READY) { + if (DEBUG) debug("Error! SIM card is not ready when sending SMS."); + errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR; + } + if (errorCode) { + if (silent) { + request.notifySendMessageFailed(errorCode); + return; + } + + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(domMessage.id, + null, + DELIVERY_STATE_ERROR, + RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, + null, + function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + request.notifySendMessageFailed(errorCode); + Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); + }); + return; + } + + // Keep current SMS message info for sent/delivered notifications + let context = { + request: request, + sms: domMessage, + requestStatusReport: options.requestStatusReport, + silent: silent + }; + + // This is the entry point starting to send SMS. + gRadioInterface.sendWorkerMessage("sendSMS", options, + (function(context, response) { + if (response.errorMsg) { + // Failed to send SMS out. + let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR; + switch (message.errorMsg) { + case RIL.ERROR_RADIO_NOT_AVAILABLE: + error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR; + break; + } + + if (context.silent) { + context.request.notifySendMessageFailed(error); + return false; + } + + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(context.sms.id, + null, + DELIVERY_STATE_ERROR, + RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, + null, + function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + context.request.notifySendMessageFailed(error); + Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); + }); + return false; + } // End of send failure. + + if (response.deliveryStatus) { + // Message delivery. + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(context.sms.id, + null, + context.sms.delivery, + message.deliveryStatus, + null, + function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS) + ? kSmsDeliverySuccessObserverTopic + : kSmsDeliveryErrorObserverTopic; + Services.obs.notifyObservers(domMessage, topic, null); + }); + + // Send transaction has ended completely. + return false; + } // End of message delivery. + + // Message sent. + if (context.silent) { + // There is no way to modify nsIDOMMozSmsMessage attributes as they are + // read only so we just create a new sms instance to send along with + // the notification. + let sms = context.sms; + context.request.notifyMessageSent( + gMobileMessageService.createSmsMessage(sms.id, + sms.threadId, + DELIVERY_STATE_SENT, + sms.deliveryStatus, + sms.sender, + sms.receiver, + sms.body, + sms.messageClass, + sms.timestamp, + sms.read)); + // We don't wait for SMS-DELIVER-REPORT for silent one. + return false; + } + + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(context.sms.id, + null, + DELIVERY_STATE_SENT, + context.sms.deliveryStatus, + null, + (function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + this._broadcastSystemMessage("sms-sent", domMessage); + + if (context.requestStatusReport) { + context.sms = domMessage; + } + + context.request.notifyMessageSent(domMessage); + Services.obs.notifyObservers(domMessage, kSmsSentObserverTopic, null); + }).bind(this)); + + // Only keep current context if we have requested for delivery report. + return context.requestStatusReport; + }).bind(this, context)); // End of |sendWorkerMessage| callback. + }).bind(this); // End of DB saveSendingMessage callback. + + let sendingMessage = { + type: "sms", + sender: this._getMsisdn(), + receiver: number, + body: message, + deliveryStatusRequested: options.requestStatusReport, + timestamp: Date.now() + }; + + if (silent) { + let deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_PENDING; + let delivery = DELIVERY_STATE_SENDING; + let domMessage = + gMobileMessageService.createSmsMessage(-1, // id + 0, // threadId + delivery, + deliveryStatus, + sendingMessage.sender, + sendingMessage.receiver, + sendingMessage.body, + "normal", // message class + sendingMessage.timestamp, + false); + notifyResult(Cr.NS_OK, domMessage); + return; + } + + let id = gMobileMessageDatabaseService.saveSendingMessage( + sendingMessage, notifyResult); + }, + + addSilentNumber: function addSilentNumber(number) { + if (this._isSilentNumber(number)) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + this.silentNumbers.push(number); + }, + + removeSilentNumber: function removeSilentNumber(number) { + let index = this.silentNumbers.indexOf(number); + if (index < 0) { + throw Cr.NS_ERROR_INVALID_ARG; + } + + this.silentNumbers.splice(index, 1); + }, + + /** + * nsIRilSmsService methods. + */ + + notifyMessageReceived: function notifyMessageReceived(message) { + if (DEBUG) debug("notifyMessageReceived: " + JSON.stringify(message)); + + // FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers + if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) { + message.fullData = new Uint8Array(message.fullData); + } + + // Dispatch to registered handler if application port addressing is + // available. Note that the destination port can possibly be zero when + // representing a UDP/TCP port. + if (message.header && message.header.destinationPort != null) { + let handler = this.portAddressedSmsApps[message.header.destinationPort]; + if (handler) { + handler(message); + } + gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK }); + return; + } + + if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) { + // Don't know how to handle binary data yet. + gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK }); + return; + } + + message.type = "sms"; + message.sender = message.sender || null; + message.receiver = this._getMsisdn(); + message.body = message.fullBody = message.fullBody || null; + message.timestamp = Date.now(); + + if (this._isSilentNumber(message.sender)) { + message.id = -1; + message.threadId = 0; + message.delivery = DELIVERY_STATE_RECEIVED; + message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS; + message.read = false; + + let domMessage = + gMobileMessageService.createSmsMessage(message.id, + message.threadId, + message.delivery, + message.deliveryStatus, + message.sender, + message.receiver, + message.body, + message.messageClass, + message.timestamp, + message.read); + + Services.obs.notifyObservers(domMessage, + kSilentSmsReceivedObserverTopic, + null); + gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK }); + return; + } + + // TODO: Bug #768441 + // For now we don't store indicators persistently. When the mwi.discard + // flag is false, we'll need to persist the indicator to EFmwis. + // See TS 23.040 9.2.3.24.2 + + let mwi = message.mwi; + if (mwi) { + mwi.returnNumber = message.sender; + mwi.returnMessage = message.fullBody; + gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification", + this.clientId, mwi); + gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK }); + return; + } + + let notifyReceived = function notifyReceived(rv, domMessage) { + let success = Components.isSuccessCode(rv); + + // Acknowledge the reception of the SMS. + gRadioInterface.sendWorkerMessage("ackSMS", { + result: (success ? RIL.PDU_FCS_OK + : RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED) + }); + + if (!success) { + // At this point we could send a message to content to notify the user + // that storing an incoming SMS failed, most likely due to a full disk. + if (DEBUG) { + debug("Could not store SMS " + message.id + ", error code " + rv); + } + return; + } + + this._broadcastSystemMessage("sms-received", domMessage); + Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null); + }.bind(this); + + if (message.messageClass == RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) { + message.id = -1; + message.threadId = 0; + message.delivery = DELIVERY_STATE_RECEIVED; + message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS; + message.read = false; + + let domMessage = + gMobileMessageService.createSmsMessage(message.id, + message.threadId, + message.delivery, + message.deliveryStatus, + message.sender, + message.receiver, + message.body, + message.messageClass, + message.timestamp, + message.read); + + notifyReceived(Cr.NS_OK, domMessage); + return; + } + + message.id = + gMobileMessageDatabaseService.saveReceivedMessage(message, + notifyReceived); + }, + + /** + * nsIObserver methods. + */ + + observe: function observe(subject, topic, data) { + switch (topic) { + case kPrefenceChangedObserverTopic: + if (data === "ril.debugging.enabled") { + try { + DEBUG = RIL.DEBUG_RIL || + Services.prefs.getBoolPref("ril.debugging.enabled"); + } catch(e) {} + } + break; + + case kXpcomShutdownObserverTopic: + Services.obs.removeObserver(this, kPrefenceChangedObserverTopic); + Services.obs.removeObserver(this, kXpcomShutdownObserverTopic); + break; + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SmsService]); diff --git a/dom/mobilemessage/src/gonk/SmsService.manifest b/dom/mobilemessage/src/gonk/SmsService.manifest new file mode 100644 index 000000000000..0275b5a2be38 --- /dev/null +++ b/dom/mobilemessage/src/gonk/SmsService.manifest @@ -0,0 +1,3 @@ +# SmsService.js +component {46a9ed78-3574-40a1-9f12-ea179942d67f} SmsService.js +contract @mozilla.org/sms/rilsmsservice;1 {46a9ed78-3574-40a1-9f12-ea179942d67f} diff --git a/dom/mobilemessage/src/ipc/SmsIPCService.cpp b/dom/mobilemessage/src/ipc/SmsIPCService.cpp index eebcbdc9a4eb..0dd5d26d29dc 100644 --- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp +++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp @@ -123,14 +123,6 @@ SmsIPCService::Send(const nsAString& aNumber, aRequest); } -NS_IMETHODIMP -SmsIPCService::IsSilentNumber(const nsAString& aNumber, - bool* aIsSilent) -{ - NS_ERROR("We should not be here!"); - return NS_ERROR_FAILURE; -} - NS_IMETHODIMP SmsIPCService::AddSilentNumber(const nsAString& aNumber) { diff --git a/dom/mobilemessage/src/moz.build b/dom/mobilemessage/src/moz.build index 505fddd8242d..fa72d68ae99d 100644 --- a/dom/mobilemessage/src/moz.build +++ b/dom/mobilemessage/src/moz.build @@ -36,6 +36,7 @@ else: CPP_SOURCES += [ 'MobileMessageDatabaseService.cpp', 'MmsService.cpp', + 'SmsService.cpp', ] EXPORTS.mozilla.dom += [ @@ -60,7 +61,6 @@ CPP_SOURCES += [ 'SmsMessage.cpp', 'SmsParent.cpp', 'SmsSegmentInfo.cpp', - 'SmsService.cpp', 'SmsServicesFactory.cpp', ] @@ -70,6 +70,8 @@ if CONFIG['MOZ_B2G_RIL']: 'gonk/MmsService.manifest', 'gonk/MobileMessageDatabaseService.js', 'gonk/MobileMessageDatabaseService.manifest', + 'gonk/SmsService.js', + 'gonk/SmsService.manifest', ] IPDL_SOURCES += [ diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index ee6547120aca..3857aeb5090f 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -47,13 +47,6 @@ const RILNETWORKINTERFACE_CID = Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}"); const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed"; -const kSmsReceivedObserverTopic = "sms-received"; -const kSilentSmsReceivedObserverTopic = "silent-sms-received"; -const kSmsSendingObserverTopic = "sms-sending"; -const kSmsSentObserverTopic = "sms-sent"; -const kSmsFailedObserverTopic = "sms-failed"; -const kSmsDeliverySuccessObserverTopic = "sms-delivery-success"; -const kSmsDeliveryErrorObserverTopic = "sms-delivery-error"; const kMozSettingsChangedObserverTopic = "mozsettings-changed"; const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready"; const kSysClockChangeObserverTopic = "system-clock-change"; @@ -119,17 +112,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService", "@mozilla.org/power/powermanagerservice;1", "nsIPowerManagerService"); -XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService", - "@mozilla.org/mobilemessage/mobilemessageservice;1", - "nsIMobileMessageService"); - XPCOMUtils.defineLazyServiceGetter(this, "gSmsService", - "@mozilla.org/sms/smsservice;1", - "nsISmsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService", - "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1", - "nsIRilMobileMessageDatabaseService"); + "@mozilla.org/sms/rilsmsservice;1", + "nsIRilSmsService"); XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", "@mozilla.org/settingsService;1", @@ -155,12 +140,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyProvider", "@mozilla.org/telephony/telephonyprovider;1", "nsIGonkTelephonyProvider"); -XPCOMUtils.defineLazyGetter(this, "WAP", function () { - let wap = {}; - Cu.import("resource://gre/modules/WapPushManager.js", wap); - return wap; -}); - XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function () { let ns = {}; Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns); @@ -467,9 +446,6 @@ function RadioInterface(options) { Services.obs.addObserver(this, kScreenStateChangedTopic, false); Services.prefs.addObserver(kCellBroadcastDisabled, this, false); - - this.portAddressedSmsApps = {}; - this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this); } RadioInterface.prototype = { @@ -697,11 +673,8 @@ RadioInterface.prototype = { this.clientId, message); break; case "sms-received": - let ackOk = this.handleSmsReceived(message); - if (ackOk) { - this.workerMessenger.send("ackSMS", { result: RIL.PDU_FCS_OK }); - } - return; + gSmsService.notifyMessageReceived(message); + break; case "cellbroadcast-received": message.timestamp = Date.now(); gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived", @@ -748,18 +721,6 @@ RadioInterface.prototype = { } }, - getMsisdn: function getMsisdn() { - let iccInfo = this.rilContext.iccInfo; - let number = iccInfo ? iccInfo.msisdn : null; - - // Workaround an xpconnect issue with undefined string objects. - // See bug 808220 - if (number === undefined || number === "undefined") { - return null; - } - return number; - }, - updateNetworkInfo: function updateNetworkInfo(message) { let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE]; let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE]; @@ -1326,184 +1287,6 @@ RadioInterface.prototype = { this.clientId, message); }, - /** - * Handle WDP port push PDU. Constructor WDP bearer information and deliver - * to WapPushManager. - * - * @param message - * A SMS message. - */ - handleSmsWdpPortPush: function handleSmsWdpPortPush(message) { - if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - if (DEBUG) { - this.debug("Got port addressed SMS but not encoded in 8-bit alphabet." + - " Drop!"); - } - return; - } - - let options = { - bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN, - sourceAddress: message.sender, - sourcePort: message.header.originatorPort, - destinationAddress: this.rilContext.iccInfo.msisdn, - destinationPort: message.header.destinationPort, - }; - WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length, - 0, options); - }, - - /** - * A helper to broadcast the system message to launch registered apps - * like Costcontrol, Notification and Message app... etc. - * - * @param aName - * The system message name. - * @param aDomMessage - * The nsIDOMMozSmsMessage object. - */ - broadcastSmsSystemMessage: function broadcastSmsSystemMessage(aName, aDomMessage) { - if (DEBUG) this.debug("Broadcasting the SMS system message: " + aName); - - // Sadly we cannot directly broadcast the aDomMessage object - // because the system message mechamism will rewrap the object - // based on the content window, which needs to know the properties. - gSystemMessenger.broadcastMessage(aName, { - type: aDomMessage.type, - id: aDomMessage.id, - threadId: aDomMessage.threadId, - delivery: aDomMessage.delivery, - deliveryStatus: aDomMessage.deliveryStatus, - sender: aDomMessage.sender, - receiver: aDomMessage.receiver, - body: aDomMessage.body, - messageClass: aDomMessage.messageClass, - timestamp: aDomMessage.timestamp, - read: aDomMessage.read - }); - }, - - portAddressedSmsApps: null, - handleSmsReceived: function handleSmsReceived(message) { - if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message)); - - // FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers - if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - message.fullData = new Uint8Array(message.fullData); - } - - // Dispatch to registered handler if application port addressing is - // available. Note that the destination port can possibly be zero when - // representing a UDP/TCP port. - if (message.header && message.header.destinationPort != null) { - let handler = this.portAddressedSmsApps[message.header.destinationPort]; - if (handler) { - handler(message); - } - return true; - } - - if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - // Don't know how to handle binary data yet. - return true; - } - - message.type = "sms"; - message.sender = message.sender || null; - message.receiver = this.getMsisdn(); - message.body = message.fullBody = message.fullBody || null; - message.timestamp = Date.now(); - - if (gSmsService.isSilentNumber(message.sender)) { - message.id = -1; - message.threadId = 0; - message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED; - message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS; - message.read = false; - - let domMessage = - gMobileMessageService.createSmsMessage(message.id, - message.threadId, - message.delivery, - message.deliveryStatus, - message.sender, - message.receiver, - message.body, - message.messageClass, - message.timestamp, - message.read); - - Services.obs.notifyObservers(domMessage, - kSilentSmsReceivedObserverTopic, - null); - return true; - } - - // TODO: Bug #768441 - // For now we don't store indicators persistently. When the mwi.discard - // flag is false, we'll need to persist the indicator to EFmwis. - // See TS 23.040 9.2.3.24.2 - - let mwi = message.mwi; - if (mwi) { - mwi.returnNumber = message.sender; - mwi.returnMessage = message.fullBody; - gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification", - this.clientId, mwi); - return true; - } - - let notifyReceived = function notifyReceived(rv, domMessage) { - let success = Components.isSuccessCode(rv); - - // Acknowledge the reception of the SMS. - this.workerMessenger.send("ackSMS", { - result: (success ? RIL.PDU_FCS_OK - : RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED) - }); - - if (!success) { - // At this point we could send a message to content to notify the user - // that storing an incoming SMS failed, most likely due to a full disk. - if (DEBUG) { - this.debug("Could not store SMS " + message.id + ", error code " + rv); - } - return; - } - - this.broadcastSmsSystemMessage("sms-received", domMessage); - Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null); - }.bind(this); - - if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) { - message.id = gMobileMessageDatabaseService.saveReceivedMessage(message, - notifyReceived); - } else { - message.id = -1; - message.threadId = 0; - message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED; - message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS; - message.read = false; - - let domMessage = - gMobileMessageService.createSmsMessage(message.id, - message.threadId, - message.delivery, - message.deliveryStatus, - message.sender, - message.receiver, - message.body, - message.messageClass, - message.timestamp, - message.read); - - notifyReceived(Cr.NS_OK, domMessage); - } - - // SMS ACK will be sent in notifyReceived. Return false here. - return false; - }, - /** * Handle data call state changes. */ @@ -1923,622 +1706,6 @@ RadioInterface.prototype = { }).bind(this)); }, - /** - * List of tuples of national language identifier pairs. - * - * TODO: Support static/runtime settings, see bug 733331. - */ - enabledGsmTableTuples: [ - [RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT], - ], - - /** - * Use 16-bit reference number for concatenated outgoint messages. - * - * TODO: Support static/runtime settings, see bug 733331. - */ - segmentRef16Bit: false, - - /** - * Get valid SMS concatenation reference number. - */ - _segmentRef: 0, - get nextSegmentRef() { - let ref = this._segmentRef++; - - this._segmentRef %= (this.segmentRef16Bit ? 65535 : 255); - - // 0 is not a valid SMS concatenation reference number. - return ref + 1; - }, - - /** - * Calculate encoded length using specified locking/single shift table - * - * @param message - * message string to be encoded. - * @param langTable - * locking shift table string. - * @param langShiftTable - * single shift table string. - * @param strict7BitEncoding - * Optional. Enable Latin characters replacement with corresponding - * ones in GSM SMS 7-bit default alphabet. - * - * @return encoded length in septets. - * - * @note that the algorithm used in this function must match exactly with - * GsmPDUHelper#writeStringAsSeptets. - */ - _countGsm7BitSeptets: function _countGsm7BitSeptets(message, langTable, langShiftTable, strict7BitEncoding) { - let length = 0; - for (let msgIndex = 0; msgIndex < message.length; msgIndex++) { - let c = message.charAt(msgIndex); - if (strict7BitEncoding) { - c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c; - } - - let septet = langTable.indexOf(c); - - // According to 3GPP TS 23.038, section 6.1.1 General notes, "The - // characters marked '1)' are not used but are displayed as a space." - if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) { - continue; - } - - if (septet >= 0) { - length++; - continue; - } - - septet = langShiftTable.indexOf(c); - if (septet < 0) { - if (!strict7BitEncoding) { - return -1; - } - - // Bug 816082, when strict7BitEncoding is enabled, we should replace - // characters that can't be encoded with GSM 7-Bit alphabets with '*'. - c = '*'; - if (langTable.indexOf(c) >= 0) { - length++; - } else if (langShiftTable.indexOf(c) >= 0) { - length += 2; - } else { - // We can't even encode a '*' character with current configuration. - return -1; - } - - continue; - } - - // According to 3GPP TS 23.038 B.2, "This code represents a control - // character and therefore must not be used for language specific - // characters." - if (septet == RIL.PDU_NL_RESERVED_CONTROL) { - continue; - } - - // The character is not found in locking shfit table, but could be - // encoded as with single shift table. Note that it's - // still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE, - // but we can display it as a space in this case as said in previous - // comment. - length += 2; - } - - return length; - }, - - /** - * Calculate user data length of specified message string encoded in GSM 7Bit - * alphabets. - * - * @param message - * a message string to be encoded. - * @param strict7BitEncoding - * Optional. Enable Latin characters replacement with corresponding - * ones in GSM SMS 7-bit default alphabet. - * - * @return null or an options object with attributes `dcs`, - * `userDataHeaderLength`, `encodedFullBodyLength`, `langIndex`, - * `langShiftIndex`, `segmentMaxSeq` set. - * - * @see #_calculateUserDataLength(). - */ - _calculateUserDataLength7Bit: function _calculateUserDataLength7Bit(message, strict7BitEncoding) { - let options = null; - let minUserDataSeptets = Number.MAX_VALUE; - for (let i = 0; i < this.enabledGsmTableTuples.length; i++) { - let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i]; - - const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; - const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; - - let bodySeptets = this._countGsm7BitSeptets(message, - langTable, - langShiftTable, - strict7BitEncoding); - if (bodySeptets < 0) { - continue; - } - - let headerLen = 0; - if (langIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) { - headerLen += 3; // IEI + len + langIndex - } - if (langShiftIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) { - headerLen += 3; // IEI + len + langShiftIndex - } - - // Calculate full user data length, note the extra byte is for header len - let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7); - let segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT; - if ((bodySeptets + headerSeptets) > segmentSeptets) { - headerLen += this.segmentRef16Bit ? 6 : 5; - headerSeptets = Math.ceil((headerLen + 1) * 8 / 7); - segmentSeptets -= headerSeptets; - } - - let segments = Math.ceil(bodySeptets / segmentSeptets); - let userDataSeptets = bodySeptets + headerSeptets * segments; - if (userDataSeptets >= minUserDataSeptets) { - continue; - } - - minUserDataSeptets = userDataSeptets; - - options = { - dcs: RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET, - encodedFullBodyLength: bodySeptets, - userDataHeaderLength: headerLen, - langIndex: langIndex, - langShiftIndex: langShiftIndex, - segmentMaxSeq: segments, - segmentChars: segmentSeptets, - }; - } - - return options; - }, - - /** - * Calculate user data length of specified message string encoded in UCS2. - * - * @param message - * a message string to be encoded. - * - * @return an options object with attributes `dcs`, `userDataHeaderLength`, - * `encodedFullBodyLength`, `segmentMaxSeq` set. - * - * @see #_calculateUserDataLength(). - */ - _calculateUserDataLengthUCS2: function _calculateUserDataLengthUCS2(message) { - let bodyChars = message.length; - let headerLen = 0; - let headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2); - let segmentChars = RIL.PDU_MAX_USER_DATA_UCS2; - if ((bodyChars + headerChars) > segmentChars) { - headerLen += this.segmentRef16Bit ? 6 : 5; - headerChars = Math.ceil((headerLen + 1) / 2); - segmentChars -= headerChars; - } - - let segments = Math.ceil(bodyChars / segmentChars); - - return { - dcs: RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET, - encodedFullBodyLength: bodyChars * 2, - userDataHeaderLength: headerLen, - segmentMaxSeq: segments, - segmentChars: segmentChars, - }; - }, - - /** - * Calculate user data length and its encoding. - * - * @param message - * a message string to be encoded. - * @param strict7BitEncoding - * Optional. Enable Latin characters replacement with corresponding - * ones in GSM SMS 7-bit default alphabet. - * - * @return an options object with some or all of following attributes set: - * - * @param dcs - * Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET - * constants. - * @param userDataHeaderLength - * Length of embedded user data header, in bytes. The whole header - * size will be userDataHeaderLength + 1; 0 for no header. - * @param encodedFullBodyLength - * Length of the message body when encoded with the given DCS. For - * UCS2, in bytes; for 7-bit, in septets. - * @param langIndex - * Table index used for normal 7-bit encoded character lookup. - * @param langShiftIndex - * Table index used for escaped 7-bit encoded character lookup. - * @param segmentMaxSeq - * Max sequence number of a multi-part messages, or 1 for single one. - * This number might not be accurate for a multi-part message until - * it's processed by #_fragmentText() again. - */ - _calculateUserDataLength: function _calculateUserDataLength(message, strict7BitEncoding) { - let options = this._calculateUserDataLength7Bit(message, strict7BitEncoding); - if (!options) { - options = this._calculateUserDataLengthUCS2(message); - } - - if (DEBUG) this.debug("_calculateUserDataLength: " + JSON.stringify(options)); - return options; - }, - - /** - * Fragment GSM 7-Bit encodable string for transmission. - * - * @param text - * text string to be fragmented. - * @param langTable - * locking shift table string. - * @param langShiftTable - * single shift table string. - * @param segmentSeptets - * Number of available spetets per segment. - * @param strict7BitEncoding - * Optional. Enable Latin characters replacement with corresponding - * ones in GSM SMS 7-bit default alphabet. - * - * @return an array of objects. See #_fragmentText() for detailed definition. - */ - _fragmentText7Bit: function _fragmentText7Bit(text, langTable, langShiftTable, segmentSeptets, strict7BitEncoding) { - let ret = []; - let body = "", len = 0; - for (let i = 0, inc = 0; i < text.length; i++) { - let c = text.charAt(i); - if (strict7BitEncoding) { - c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c; - } - - let septet = langTable.indexOf(c); - if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) { - continue; - } - - if (septet >= 0) { - inc = 1; - } else { - septet = langShiftTable.indexOf(c); - if (septet == RIL.PDU_NL_RESERVED_CONTROL) { - continue; - } - - inc = 2; - if (septet < 0) { - if (!strict7BitEncoding) { - throw new Error("Given text cannot be encoded with GSM 7-bit Alphabet!"); - } - - // Bug 816082, when strict7BitEncoding is enabled, we should replace - // characters that can't be encoded with GSM 7-Bit alphabets with '*'. - c = '*'; - if (langTable.indexOf(c) >= 0) { - inc = 1; - } - } - } - - if ((len + inc) > segmentSeptets) { - ret.push({ - body: body, - encodedBodyLength: len, - }); - body = c; - len = inc; - } else { - body += c; - len += inc; - } - } - - if (len) { - ret.push({ - body: body, - encodedBodyLength: len, - }); - } - - return ret; - }, - - /** - * Fragment UCS2 encodable string for transmission. - * - * @param text - * text string to be fragmented. - * @param segmentChars - * Number of available characters per segment. - * - * @return an array of objects. See #_fragmentText() for detailed definition. - */ - _fragmentTextUCS2: function _fragmentTextUCS2(text, segmentChars) { - let ret = []; - for (let offset = 0; offset < text.length; offset += segmentChars) { - let str = text.substr(offset, segmentChars); - ret.push({ - body: str, - encodedBodyLength: str.length * 2, - }); - } - - return ret; - }, - - /** - * Fragment string for transmission. - * - * Fragment input text string into an array of objects that contains - * attributes `body`, substring for this segment, `encodedBodyLength`, - * length of the encoded segment body in septets. - * - * @param text - * Text string to be fragmented. - * @param options - * Optional pre-calculated option object. The output array will be - * stored at options.segments if there are multiple segments. - * @param strict7BitEncoding - * Optional. Enable Latin characters replacement with corresponding - * ones in GSM SMS 7-bit default alphabet. - * - * @return Populated options object. - */ - _fragmentText: function _fragmentText(text, options, strict7BitEncoding) { - if (!options) { - options = this._calculateUserDataLength(text, strict7BitEncoding); - } - - if (options.dcs == RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[options.langIndex]; - const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[options.langShiftIndex]; - options.segments = this._fragmentText7Bit(text, - langTable, langShiftTable, - options.segmentChars, - strict7BitEncoding); - } else { - options.segments = this._fragmentTextUCS2(text, - options.segmentChars); - } - - // Re-sync options.segmentMaxSeq with actual length of returning array. - options.segmentMaxSeq = options.segments.length; - - return options; - }, - - getSegmentInfoForText: function getSegmentInfoForText(text) { - let strict7BitEncoding; - try { - strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding"); - } catch (e) { - strict7BitEncoding = false; - } - - let options = this._fragmentText(text, null, strict7BitEncoding); - let charsInLastSegment; - if (options.segmentMaxSeq) { - let lastSegment = options.segments[options.segmentMaxSeq - 1]; - charsInLastSegment = lastSegment.encodedBodyLength; - if (options.dcs == RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET) { - // In UCS2 encoding, encodedBodyLength is in octets. - charsInLastSegment /= 2; - } - } else { - charsInLastSegment = 0; - } - - let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq, - options.segmentChars, - options.segmentChars - charsInLastSegment); - return result; - }, - - sendSMS: function sendSMS(number, message, silent, request) { - let strict7BitEncoding; - try { - strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding"); - } catch (e) { - strict7BitEncoding = false; - } - - let options = this._fragmentText(message, null, strict7BitEncoding); - options.number = PhoneNumberUtils.normalize(number); - let requestStatusReport; - try { - requestStatusReport = - Services.prefs.getBoolPref("dom.sms.requestStatusReport"); - } catch (e) { - requestStatusReport = true; - } - options.requestStatusReport = requestStatusReport && !silent; - if (options.segmentMaxSeq > 1) { - options.segmentRef16Bit = this.segmentRef16Bit; - options.segmentRef = this.nextSegmentRef; - } - - let notifyResult = (function notifyResult(rv, domMessage) { - // TODO bug 832140 handle !Components.isSuccessCode(rv) - if (!silent) { - Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null); - } - - // If the radio is disabled or the SIM card is not ready, just directly - // return with the corresponding error code. - let errorCode; - if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) { - if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " + - options.number); - errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR; - } else if (!this._radioEnabled) { - if (DEBUG) this.debug("Error! Radio is disabled when sending SMS."); - errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR; - } else if (this.rilContext.cardState != "ready") { - if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS."); - errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR; - } - if (errorCode) { - if (silent) { - request.notifySendMessageFailed(errorCode); - return; - } - - gMobileMessageDatabaseService - .setMessageDeliveryByMessageId(domMessage.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_ERROR, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, - null, - function notifyResult(rv, domMessage) { - // TODO bug 832140 handle !Components.isSuccessCode(rv) - request.notifySendMessageFailed(errorCode); - Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); - }); - return; - } - - // Keep current SMS message info for sent/delivered notifications - let context = { - request: request, - sms: domMessage, - requestStatusReport: options.requestStatusReport, - silent: silent - }; - - // This is the entry point starting to send SMS. - this.workerMessenger.send("sendSMS", options, - (function(context, response) { - if (response.errorMsg) { - // Failed to send SMS out. - let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR; - switch (message.errorMsg) { - case RIL.ERROR_RADIO_NOT_AVAILABLE: - error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR; - break; - } - - if (context.silent) { - context.request.notifySendMessageFailed(error); - return false; - } - - gMobileMessageDatabaseService - .setMessageDeliveryByMessageId(context.sms.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_ERROR, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, - null, - function notifyResult(rv, domMessage) { - // TODO bug 832140 handle !Components.isSuccessCode(rv) - context.request.notifySendMessageFailed(error); - Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); - }); - return false; - } // End of send failure. - - if (response.deliveryStatus) { - // Message delivery. - gMobileMessageDatabaseService - .setMessageDeliveryByMessageId(context.sms.id, - null, - context.sms.delivery, - response.deliveryStatus, - null, - function notifyResult(rv, domMessage) { - // TODO bug 832140 handle !Components.isSuccessCode(rv) - let topic = (response.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS) - ? kSmsDeliverySuccessObserverTopic - : kSmsDeliveryErrorObserverTopic; - Services.obs.notifyObservers(domMessage, topic, null); - }); - - // Send transaction has ended completely. - return false; - } // End of message delivery. - - // Message sent. - if (context.silent) { - // There is no way to modify nsIDOMMozSmsMessage attributes as they are - // read only so we just create a new sms instance to send along with - // the notification. - let sms = context.sms; - context.request.notifyMessageSent( - gMobileMessageService.createSmsMessage(sms.id, - sms.threadId, - DOM_MOBILE_MESSAGE_DELIVERY_SENT, - sms.deliveryStatus, - sms.sender, - sms.receiver, - sms.body, - sms.messageClass, - sms.timestamp, - sms.read)); - // We don't wait for SMS-DELIVER-REPORT for silent one. - return false; - } - - gMobileMessageDatabaseService - .setMessageDeliveryByMessageId(context.sms.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_SENT, - context.sms.deliveryStatus, - null, - (function notifyResult(rv, domMessage) { - // TODO bug 832140 handle !Components.isSuccessCode(rv) - this.broadcastSmsSystemMessage("sms-sent", domMessage); - - if (context.requestStatusReport) { - context.sms = domMessage; - } - - context.request.notifyMessageSent(domMessage); - Services.obs.notifyObservers(domMessage, kSmsSentObserverTopic, null); - }).bind(this)); - - // Only keep current context if we have requested for delivery report. - return context.requestStatusReport; - }).bind(this, context)); // End of |workerMessenger.send| callback. - }).bind(this); // End of DB saveSendingMessage callback. - - let sendingMessage = { - type: "sms", - sender: this.getMsisdn(), - receiver: number, - body: message, - deliveryStatusRequested: options.requestStatusReport, - timestamp: Date.now() - }; - - if (silent) { - let deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_PENDING; - let delivery = DOM_MOBILE_MESSAGE_DELIVERY_SENDING; - let domMessage = - gMobileMessageService.createSmsMessage(-1, // id - 0, // threadId - delivery, - deliveryStatus, - sendingMessage.sender, - sendingMessage.receiver, - sendingMessage.body, - "normal", // message class - sendingMessage.timestamp, - false); - notifyResult(Cr.NS_OK, domMessage); - return; - } - - let id = gMobileMessageDatabaseService.saveSendingMessage( - sendingMessage, notifyResult); - }, - registerDataCallCallback: function registerDataCallCallback(callback) { if (this._datacall_callbacks) { if (this._datacall_callbacks.indexOf(callback) != -1) { diff --git a/dom/system/gonk/nsIRadioInterfaceLayer.idl b/dom/system/gonk/nsIRadioInterfaceLayer.idl index c9c7eeb51ae8..770c1e1acf77 100644 --- a/dom/system/gonk/nsIRadioInterfaceLayer.idl +++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl @@ -6,8 +6,6 @@ interface nsIDOMMozIccInfo; interface nsIDOMMozMobileConnectionInfo; -interface nsIDOMMozSmsSegmentInfo; -interface nsIMobileMessageCallback; [scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)] interface nsIRILDataCallInfo : nsISupports @@ -85,7 +83,7 @@ interface nsIRilSendWorkerMessageCallback : nsISupports boolean handleResponse(in jsval response); }; -[scriptable, uuid(61a8ca67-6113-4cd0-b443-e045f09863ed)] +[scriptable, uuid(b1af7aad-6547-427c-a878-e2ebf98a14d6)] interface nsIRadioInterface : nsISupports { readonly attribute nsIRilContext rilContext; @@ -102,16 +100,6 @@ interface nsIRadioInterface : nsISupports void updateRILNetworkInterface(); - /** - * SMS-related functionality. - */ - nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text); - - void sendSMS(in DOMString number, - in DOMString message, - in boolean silent, - in nsIMobileMessageCallback request); - void sendWorkerMessage(in DOMString type, [optional] in jsval message, [optional] in nsIRilSendWorkerMessageCallback callback);