Merge m-i into m-c.
authorMounir Lamouri <mounir.lamouri@gmail.com>
Wed, 18 Jan 2012 11:28:32 +0100
changeset 86004 7538f4d4697c67c34ce17cb567a35133eb4cb1bc
parent 85924 f4049f65efc6e367c54643ad7c66b3e81e24bac5 (current diff)
parent 86003 715e4b7e3b51fded840bec05b9294cc9b8506feb (diff)
child 86011 f93675b9e0ac52a581a549e135c4c5631cdd761d
child 86018 2813a0ddc819fb89f977bb8d7636e74a10248001
push idunknown
push userunknown
push dateunknown
milestone12.0a1
Merge m-i into m-c.
dom/sms/src/SmsServiceFactory.cpp
dom/sms/src/SmsServiceFactory.h
xpcom/ds/nsIRecyclingAllocator.idl
xpcom/ds/nsRecyclingAllocator.cpp
xpcom/ds/nsRecyclingAllocator.h
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -151,16 +151,17 @@
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
+@BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_range.xpt
 @BINPATH@/components/dom_sidebar.xpt
 @BINPATH@/components/dom_sms.xpt
--- a/browser/components/preferences/main.js
+++ b/browser/components/preferences/main.js
@@ -366,17 +366,17 @@ var gMainPane = {
       // With 3.0, a new desktop folder - 'Downloads' was introduced for
       // platforms and versions that don't support a default system downloads
       // folder. See nsDownloadManager for details. 
       downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
       iconUrlSpec = fph.getURLSpecFromFile(this._indexToFolder(1));
     } else {
       // 'Desktop'
       downloadFolder.label = bundlePreferences.getString("desktopFolderName");
-      iconUrlSpec = fph.getURLSpecFromFile(desk);
+      iconUrlSpec = fph.getURLSpecFromFile(this._getDownloadsFolder("Desktop"));
     }
     downloadFolder.image = "moz-icon://" + iconUrlSpec + "?size=16";
     
     // don't override the preference's value in UI
     return undefined;
   },
 
   /**
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -141,16 +141,17 @@
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
+@BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_range.xpt
 @BINPATH@/components/dom_sidebar.xpt
 @BINPATH@/components/dom_sms.xpt
--- a/browser/installer/windows/nsis/maintenanceservice_installer.nsi
+++ b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -116,19 +116,18 @@ ShowUnInstDetails nevershow
 !define MUI_UNICON setup.ico
 !define MUI_WELCOMEPAGE_TITLE_3LINES
 !define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
 
 ;Interface Settings
 !define MUI_ABORTWARNING
 
 ; Uninstaller Pages
-!insertmacro MUI_UNPAGE_WELCOME
+!insertmacro MUI_UNPAGE_CONFIRM
 !insertmacro MUI_UNPAGE_INSTFILES
-!insertmacro MUI_UNPAGE_FINISH
 
 ################################################################################
 # Language
 
 !insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
 !verbose push
 !verbose 3
 !include "overrideLocale.nsh"
@@ -252,16 +251,18 @@ FunctionEnd
 Section "Uninstall"
   ; Delete the service so that no updates will be attempted
   nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
 
   Push "$INSTDIR\maintenanceservice.exe"
   Call un.RenameDelete
   Push "$INSTDIR\maintenanceservice_tmp.exe"
   Call un.RenameDelete
+  Push "$INSTDIR\maintenanceservice.old"
+  Call un.RenameDelete
   Push "$INSTDIR\Uninstall.exe"
   Call un.RenameDelete
   RMDir /REBOOTOK "$INSTDIR"
 
   DeleteRegKey HKLM "${MaintUninstallKey}"
 
   SetRegView 64
   DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed"
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -141,16 +141,17 @@ MOZ_INSTALLER	= @MOZ_INSTALLER@
 MOZ_MAINTENANCE_SERVICE	= @MOZ_MAINTENANCE_SERVICE@
 MOZ_UPDATER	= @MOZ_UPDATER@
 MOZ_UPDATE_CHANNEL	= @MOZ_UPDATE_CHANNEL@
 MOZ_UPDATE_PACKAGING	= @MOZ_UPDATE_PACKAGING@
 MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
 NS_ENABLE_TSF = @NS_ENABLE_TSF@
 MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
 MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
+MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
 MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@
 MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
 MOZ_FEEDS = @MOZ_FEEDS@
 MOZ_TOOLKIT_SEARCH = @MOZ_TOOLKIT_SEARCH@
 MOZ_PLACES = @MOZ_PLACES@
 MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@
 MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@
 MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
--- a/configure.in
+++ b/configure.in
@@ -4624,16 +4624,17 @@ MOZ_DISABLE_DOMCRYPTO=
 NSS_DISABLE_DBM=
 NECKO_WIFI=1
 NECKO_COOKIES=1
 NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciwyg device"
 USE_ARM_KUSER=
 BUILD_CTYPES=1
 MOZ_USE_NATIVE_POPUP_WINDOWS=
 MOZ_ANDROID_HISTORY=
+MOZ_WEBSMS_BACKEND=1
 MOZ_GRAPHITE=1
 
 case "${target}" in
 *darwin*)
     ACCESSIBILITY=
     ;;
 *)
     ACCESSIBILITY=1
@@ -5460,16 +5461,28 @@ AC_SUBST(MOZ_DBUS_GLIB_LIBS)
 dnl ========================================================
 dnl = Enable Android History instead of Places
 dnl ========================================================
 if test -n "$MOZ_ANDROID_HISTORY"; then
      dnl Do this if defined in confvars.sh
      AC_DEFINE(MOZ_ANDROID_HISTORY)
 fi
 
+dnl ========================================================
+dnl = Disable WebSMS backend
+dnl ========================================================
+MOZ_ARG_DISABLE_BOOL(websms-backend,
+[  --disable-websms-backend
+                           Disable WebSMS backend],
+    MOZ_WEBSMS_BACKEND=,
+    MOZ_WEBSMS_BACKEND=1)
+
+if test $MOZ_WEBSMS_BACKEND -eq 1; then
+    AC_DEFINE(MOZ_WEBSMS_BACKEND)
+fi
 
 dnl ========================================================
 dnl = Build Personal Security Manager
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(crypto,
 [  --disable-crypto        Disable crypto support (Personal Security Manager)],
     MOZ_PSM=,
     MOZ_PSM=1 )
@@ -8440,16 +8453,17 @@ AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX)
 AC_SUBST(MOZ_D3DX9_VERSION)
 AC_SUBST(MOZ_D3DX9_CAB)
 AC_SUBST(MOZ_D3DCOMPILER_CAB)
 AC_SUBST(MOZ_D3DX9_DLL)
 AC_SUBST(MOZ_D3DCOMPILER_DLL)
 
 AC_SUBST(MOZ_ANDROID_HISTORY)
+AC_SUBST(MOZ_WEBSMS_BACKEND)
 AC_SUBST(ENABLE_STRIP)
 AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(USE_ELF_DYNSTR_GC)
 AC_SUBST(USE_ELF_HACK)
 AC_SUBST(INCREMENTAL_LINKER)
 AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
 AC_SUBST(MOZ_COMPONENT_NSPR_LIBS)
 
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -70,16 +70,17 @@ DIRS = \
   $(NULL)
 
 DIRS += \
   base \
   battery \
   sms \
   src \
   locales \
+  network \
   plugins/base \
   plugins/ipc \
   indexedDB \
   system \
   ipc \
   workers \
   $(NULL)
 
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -69,16 +69,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
 #include "SmsManager.h"
 #include "nsISmsService.h"
 #include "mozilla/Hal.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "Connection.h"
 
 #ifdef MOZ_B2G_RIL
 #include "TelephonyFactory.h"
 #endif
 
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
@@ -125,16 +126,17 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
   NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorBattery)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorSms)
 #ifdef MOZ_B2G_RIL
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorTelephony)
 #endif
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorNetwork)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(Navigator)
 NS_IMPL_RELEASE(Navigator)
 
 void
 Navigator::Invalidate()
@@ -167,16 +169,21 @@ Navigator::Invalidate()
     mSmsManager = nsnull;
   }
 
 #ifdef MOZ_B2G_RIL
   if (mTelephony) {
     mTelephony = nsnull;
   }
 #endif
+
+  if (mConnection) {
+    mConnection->Shutdown();
+    mConnection = nsnull;
+  }
 }
 
 nsPIDOMWindow *
 Navigator::GetWindow()
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
   return win;
@@ -989,23 +996,27 @@ Navigator::IsSmsAllowed() const
 
   // The current page hasn't been whitelisted.
   return false;
 }
 
 bool
 Navigator::IsSmsSupported() const
 {
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+#ifdef MOZ_WEBSMS_BACKEND
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, false);
 
   bool result = false;
   smsService->HasSupport(&result);
 
   return result;
+#else
+  return false;
+#endif
 }
 
 NS_IMETHODIMP
 Navigator::GetMozSms(nsIDOMMozSmsManager** aSmsManager)
 {
   *aSmsManager = nsnull;
 
   if (!mSmsManager) {
@@ -1054,16 +1065,43 @@ Navigator::GetMozTelephony(nsIDOMTelepho
   }
 
   telephony.forget(aTelephony);
   return NS_OK;
 }
 
 #endif // MOZ_B2G_RIL
 
+//*****************************************************************************
+//    Navigator::nsIDOMNavigatorNetwork
+//*****************************************************************************
+
+NS_IMETHODIMP
+Navigator::GetMozConnection(nsIDOMMozConnection** aConnection)
+{
+  *aConnection = nsnull;
+
+  if (!mConnection) {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
+
+    nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
+    NS_ENSURE_TRUE(sgo, NS_OK);
+
+    nsIScriptContext* scx = sgo->GetContext();
+    NS_ENSURE_TRUE(scx, NS_OK);
+
+    mConnection = new network::Connection();
+    mConnection->Init(window, scx);
+  }
+
+  NS_ADDREF(*aConnection = mConnection);
+  return NS_OK;
+}
+
 PRInt64
 Navigator::SizeOf() const
 {
   PRInt64 size = sizeof(*this);
 
   // TODO: add SizeOf() to nsMimeTypeArray, bug 674113.
   size += mMimeTypes ? sizeof(*mMimeTypes.get()) : 0;
   // TODO: add SizeOf() to nsPluginArray, bug 674114.
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -44,24 +44,26 @@
 #define mozilla_dom_Navigator_h
 
 #include "nsIDOMNavigator.h"
 #include "nsIDOMNavigatorGeolocation.h"
 #include "nsIDOMNavigatorDesktopNotification.h"
 #include "nsIDOMClientInformation.h"
 #include "nsIDOMNavigatorBattery.h"
 #include "nsIDOMNavigatorSms.h"
+#include "nsIDOMNavigatorNetwork.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsGeolocation;
 class nsDesktopNotificationCenter;
 class nsPIDOMWindow;
+class nsIDOMMozConnection;
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMNavigatorTelephony.h"
 class nsIDOMTelephony;
 #endif
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
@@ -73,41 +75,46 @@ namespace dom {
 namespace battery {
 class BatteryManager;
 } // namespace battery
 
 namespace sms {
 class SmsManager;
 } // namespace sms
 
-class Navigator : public nsIDOMNavigator,
-                  public nsIDOMClientInformation,
-                  public nsIDOMNavigatorGeolocation,
-                  public nsIDOMNavigatorDesktopNotification,
-                  public nsIDOMMozNavigatorBattery,
-                  public nsIDOMMozNavigatorSms
+namespace network {
+class Connection;
+} // namespace Connection;
+
+class Navigator : public nsIDOMNavigator
+                , public nsIDOMClientInformation
+                , public nsIDOMNavigatorGeolocation
+                , public nsIDOMNavigatorDesktopNotification
+                , public nsIDOMMozNavigatorBattery
+                , public nsIDOMMozNavigatorSms
 #ifdef MOZ_B2G_RIL
                 , public nsIDOMNavigatorTelephony
 #endif
+                , public nsIDOMMozNavigatorNetwork
 {
 public:
   Navigator(nsPIDOMWindow *aInnerWindow);
   virtual ~Navigator();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMNAVIGATOR
   NS_DECL_NSIDOMCLIENTINFORMATION
   NS_DECL_NSIDOMNAVIGATORGEOLOCATION
   NS_DECL_NSIDOMNAVIGATORDESKTOPNOTIFICATION
   NS_DECL_NSIDOMMOZNAVIGATORBATTERY
   NS_DECL_NSIDOMMOZNAVIGATORSMS
-
 #ifdef MOZ_B2G_RIL
   NS_DECL_NSIDOMNAVIGATORTELEPHONY
 #endif
+  NS_DECL_NSIDOMMOZNAVIGATORNETWORK
 
   static void Init();
 
   void Invalidate();
   nsPIDOMWindow *GetWindow();
 
   void RefreshMIMEArray();
 
@@ -128,16 +135,17 @@ private:
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<nsGeolocation> mGeolocation;
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
 #ifdef MOZ_B2G_RIL
   nsCOMPtr<nsIDOMTelephony> mTelephony;
 #endif
+  nsRefPtr<network::Connection> mConnection;
   nsWeakPtr mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -34,16 +34,21 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/Util.h"
+#include "SmsFilter.h" // On top because it includes basictypes.h.
+
+#ifdef XP_WIN
+#undef GetClassName
+#endif
 
 // JavaScript includes
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsprvtd.h"    // we are using private JS typedefs...
 #include "jsdbgapi.h"
 #include "WrapperFactory.h"
 #include "AccessCheck.h"
@@ -159,21 +164,16 @@
 #include "nsIDOMHTMLSelectElement.h"
 
 // HTMLEmbed/ObjectElement helper includes
 #include "nsNPAPIPluginInstance.h"
 #include "nsIObjectFrame.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIPluginHost.h"
 
-// Oh, did I mention that I hate Microsoft for doing this to me?
-#ifdef XP_WIN
-#undef GetClassName
-#endif
-
 // HTMLOptionsCollection includes
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsIDOMHTMLOptionsCollection.h"
 
 // ContentList includes
 #include "nsContentList.h"
 #include "nsGenericElement.h"
 
@@ -509,17 +509,22 @@
 #include "nsWrapperCacheInlines.h"
 #include "dombindings.h"
 
 #include "nsIDOMBatteryManager.h"
 #include "BatteryManager.h"
 #include "nsIDOMSmsManager.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsIDOMSmsEvent.h"
+#include "nsIDOMSmsRequest.h"
+#include "nsIDOMSmsFilter.h"
+#include "nsIDOMSmsCursor.h"
 #include "nsIPrivateDOMEvent.h"
+#include "nsIDOMConnection.h"
+#include "mozilla/dom/network/Utils.h"
 
 #ifdef MOZ_B2G_RIL
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "CallEvent.h"
 #endif
 
 using namespace mozilla;
@@ -1406,16 +1411,28 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozSmsEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
+  NS_DEFINE_CLASSINFO_DATA(MozSmsRequest, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(MozSmsFilter, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(MozSmsCursor, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(MozConnection, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
   NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSFontFaceStyleDecl, nsCSSStyleDeclSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 
 #if defined(MOZ_MEDIA)
   NS_DEFINE_CLASSINFO_DATA(HTMLVideoElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
@@ -1632,16 +1649,17 @@ static const nsConstructorFuncMapData kC
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CustomEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PopStateEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
 };
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull;
 nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nsnull;
 bool nsDOMClassInfo::sIsInitialized = false;
 bool nsDOMClassInfo::sDisableDocumentAllSupport = false;
 bool nsDOMClassInfo::sDisableGlobalScopePollutionSupport = false;
 
@@ -2354,16 +2372,18 @@ nsDOMClassInfo::Init()
                                         Navigator::HasDesktopNotificationSupport())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMClientInformation)
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorBattery,
                                         battery::BatteryManager::HasSupport())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozNavigatorSms)
 #ifdef MOZ_B2G_RIL
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorTelephony)
 #endif
+    DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorNetwork,
+                                        network::IsAPIEnabled())
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPlugin)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PluginArray, nsIDOMPluginArray)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPluginArray)
@@ -3981,16 +4001,33 @@ nsDOMClassInfo::Init()
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozSmsEvent, nsIDOMMozSmsEvent)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsEvent)
      DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(MozSmsRequest, nsIDOMMozSmsRequest)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsRequest)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(MozSmsFilter, nsIDOMMozSmsFilter)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsFilter)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(MozSmsCursor, nsIDOMMozSmsCursor)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsCursor)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(MozConnection, nsIDOMMozConnection)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozConnection)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSFontFaceStyleDecl,
                                       nsIDOMCSSStyleDeclaration)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleDeclaration)
   DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -428,16 +428,21 @@ DOMCI_CLASS(GeoPositionCoords)
 DOMCI_CLASS(GeoPositionAddress)
 DOMCI_CLASS(GeoPositionError)
 
 DOMCI_CLASS(MozBatteryManager)
 
 DOMCI_CLASS(MozSmsManager)
 DOMCI_CLASS(MozSmsMessage)
 DOMCI_CLASS(MozSmsEvent)
+DOMCI_CLASS(MozSmsRequest)
+DOMCI_CLASS(MozSmsFilter)
+DOMCI_CLASS(MozSmsCursor)
+
+DOMCI_CLASS(MozConnection)
 
 // @font-face in CSS
 DOMCI_CLASS(CSSFontFaceRule)
 DOMCI_CLASS(CSSFontFaceStyleDecl)
 
 #if defined(MOZ_MEDIA)
 // WhatWG Video Element
 DOMCI_CLASS(HTMLVideoElement)
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -1,11 +1,12 @@
 DOM_SRCDIRS = \
   dom/base \
   dom/battery \
+  dom/network/src \
   dom/sms/src \
   dom/src/events \
   dom/src/storage \
   dom/src/offline \
   dom/src/geolocation \
   dom/src/notification \
   dom/workers \
   content/xbl/src \
new file mode 100644
--- /dev/null
+++ b/dom/network/Makefile.in
@@ -0,0 +1,50 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH            = ../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+PARALLEL_DIRS = interfaces src
+
+ifdef ENABLE_TESTS
+DIRS += tests
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/Makefile.in
@@ -0,0 +1,53 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH            = ../../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+XPIDL_MODULE = dom_network
+
+include $(topsrcdir)/dom/dom-config.mk
+
+XPIDLSRCS = \
+  nsIDOMNavigatorNetwork.idl \
+  nsIDOMConnection.idl \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsIDOMConnection.idl
@@ -0,0 +1,48 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIDOMEventListener;
+
+[scriptable, uuid(8c6b574d-1135-4387-a6e3-6d8ba38d79a1)]
+interface nsIDOMMozConnection : nsISupports
+{
+  readonly attribute double  bandwidth;
+  readonly attribute boolean metered;
+
+           attribute nsIDOMEventListener onchange;
+};
new file mode 100644
--- /dev/null
+++ b/dom/network/interfaces/nsIDOMNavigatorNetwork.idl
@@ -0,0 +1,45 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIDOMMozConnection;
+
+[scriptable, uuid(1dd6773e-30dc-419b-9766-b05458fd96c8)]
+interface nsIDOMMozNavigatorNetwork : nsISupports
+{
+  readonly attribute nsIDOMMozConnection mozConnection;
+};
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Connection.cpp
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <limits>
+#include "mozilla/Hal.h"
+#include "Connection.h"
+#include "nsIDOMClassInfo.h"
+#include "mozilla/Preferences.h"
+#include "nsDOMEvent.h"
+#include "Constants.h"
+
+/**
+ * We have to use macros here because our leak analysis tool things we are
+ * leaking strings when we have |static const nsString|. Sad :(
+ */
+#define CHANGE_EVENT_NAME NS_LITERAL_STRING("change")
+
+DOMCI_DATA(MozConnection, mozilla::dom::network::Connection)
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+const char* Connection::sMeteredPrefName     = "dom.network.metered";
+const bool  Connection::sMeteredDefaultValue = false;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Connection)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Connection,
+                                                  nsDOMEventTargetWrapperCache)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Connection,
+                                                nsDOMEventTargetWrapperCache)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Connection)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozConnection)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozConnection)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozConnection)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+
+NS_IMPL_ADDREF_INHERITED(Connection, nsDOMEventTargetWrapperCache)
+NS_IMPL_RELEASE_INHERITED(Connection, nsDOMEventTargetWrapperCache)
+
+Connection::Connection()
+  : mCanBeMetered(kDefaultCanBeMetered)
+  , mBandwidth(kDefaultBandwidth)
+{
+}
+
+void
+Connection::Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext)
+{
+  // Those vars come from nsDOMEventTargetHelper.
+  mOwner = aWindow;
+  mScriptContext = aScriptContext;
+
+  hal::RegisterNetworkObserver(this);
+
+  hal::NetworkInformation networkInfo;
+  hal::GetCurrentNetworkInformation(&networkInfo);
+
+  UpdateFromNetworkInfo(networkInfo);
+}
+
+void
+Connection::Shutdown()
+{
+  hal::UnregisterNetworkObserver(this);
+}
+
+NS_IMETHODIMP
+Connection::GetBandwidth(double* aBandwidth)
+{
+  if (mBandwidth == kDefaultBandwidth) {
+    *aBandwidth = std::numeric_limits<double>::infinity();
+    return NS_OK;
+  }
+
+  *aBandwidth = mBandwidth;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Connection::GetMetered(bool* aMetered)
+{
+  if (!mCanBeMetered) {
+    *aMetered = false;
+    return NS_OK;
+  }
+
+  *aMetered = Preferences::GetBool(sMeteredPrefName,
+                                   sMeteredDefaultValue);
+  return NS_OK;
+}
+
+NS_IMPL_EVENT_HANDLER(Connection, change)
+
+nsresult
+Connection::DispatchTrustedEventToSelf(const nsAString& aEventName)
+{
+  nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
+  nsresult rv = event->InitEvent(aEventName, false, false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = event->SetTrusted(PR_TRUE);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool dummy;
+  rv = DispatchEvent(event, &dummy);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+void
+Connection::UpdateFromNetworkInfo(const hal::NetworkInformation& aNetworkInfo)
+{
+  mBandwidth = aNetworkInfo.bandwidth();
+  mCanBeMetered = aNetworkInfo.canBeMetered();
+}
+
+void
+Connection::Notify(const hal::NetworkInformation& aNetworkInfo)
+{
+  double previousBandwidth = mBandwidth;
+  bool previousCanBeMetered = mCanBeMetered;
+
+  UpdateFromNetworkInfo(aNetworkInfo);
+
+  if (previousBandwidth == mBandwidth &&
+      previousCanBeMetered == mCanBeMetered) {
+    return;
+  }
+
+  DispatchTrustedEventToSelf(CHANGE_EVENT_NAME);
+}
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Connection.h
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_network_Connection_h
+#define mozilla_dom_network_Connection_h
+
+#include "nsIDOMConnection.h"
+#include "nsDOMEventTargetWrapperCache.h"
+#include "nsCycleCollectionParticipant.h"
+#include "mozilla/Observer.h"
+#include "Types.h"
+
+namespace mozilla {
+
+namespace hal {
+class NetworkInformation;
+} // namespace hal
+
+namespace dom {
+namespace network {
+
+class Connection : public nsDOMEventTargetWrapperCache
+                 , public nsIDOMMozConnection
+                 , public NetworkObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMMOZCONNECTION
+
+  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
+
+  Connection();
+
+  void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
+  void Shutdown();
+
+  // For IObserver
+  void Notify(const hal::NetworkInformation& aNetworkInfo);
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Connection,
+                                           nsDOMEventTargetWrapperCache)
+
+private:
+  /**
+   * Dispatch a trusted non-cancellable and non-bubbling event to itself.
+   */
+  nsresult DispatchTrustedEventToSelf(const nsAString& aEventName);
+
+  /**
+   * Update the connection information stored in the object using a
+   * NetworkInformation object.
+   */
+  void UpdateFromNetworkInfo(const hal::NetworkInformation& aNetworkInfo);
+
+  /**
+   * If the connection is of a type that can be metered.
+   */
+  bool mCanBeMetered;
+
+  /**
+   * The connection bandwidth.
+   */
+  double mBandwidth;
+
+  NS_DECL_EVENT_HANDLER(change)
+
+  static const char* sMeteredPrefName;
+  static const bool  sMeteredDefaultValue;
+};
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Connection_h
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Constants.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_network_Constants_h__
+#define mozilla_dom_network_Constants_h__
+
+/**
+ * A set of constants to be used by network backends.
+ */
+namespace mozilla {
+namespace dom {
+namespace network {
+
+  static const double kDefaultBandwidth    = -1.0;
+  static const bool   kDefaultCanBeMetered = false;
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Constants_h__
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Makefile.in
@@ -0,0 +1,69 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH            = ../../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = $(srcdir)
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME     = dom_network_s
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/dom/dom-config.mk
+
+EXPORTS_NAMESPACES = mozilla/dom/network
+
+EXPORTS_mozilla/dom/network = \
+  Utils.h \
+  Types.h \
+  Constants.h \
+  $(NULL)
+
+CPPSRCS = \
+  Connection.cpp \
+  Utils.cpp \
+  $(NULL)
+
+LOCAL_INCLUDES = \
+  -I$(topsrcdir)/content/events/src \
+  $(NULL)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Types.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_network_Types_h
+#define mozilla_dom_network_Types_h
+
+namespace mozilla {
+namespace hal {
+class NetworkInformation;
+} // namespace hal
+
+template <class T>
+class Observer;
+
+typedef Observer<hal::NetworkInformation> NetworkObserver;
+
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Types_h
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Utils.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "Utils.h"
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+/* extern */ bool
+IsAPIEnabled()
+{
+  return Preferences::GetBool("dom.network.enabled", true);
+}
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/network/src/Utils.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_network_Utils_h
+#define mozilla_dom_network_Utils_h
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+/**
+ * Returns whether the Network API is enabled.
+ * @return whether the Network API is enabled.
+ */
+extern bool IsAPIEnabled();
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_Utils_h
+
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/Makefile.in
@@ -0,0 +1,62 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH            = ../../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+relativesrcdir   = dom/network/tests
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+  test_network_basics.html \
+  $(NULL)
+
+_CHROME_TEST_FILES = \
+  $(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
+#libs:: $(_CHROME_TEST_FILES)
+#	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/test_network_basics.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Network API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Network API **/
+
+function checkInterface(aInterface) {
+  ok(!(aInterface in window), aInterface + " should be prefixed");
+  ok(("Moz" + aInterface) in window, aInterface + " should be prefixed");
+}
+
+ok('mozConnection' in navigator, "navigator.mozConnection should exist");
+
+ok(navigator.mozConnection, "navigator.mozConnection returns an object");
+
+ok(navigator.mozConnection instanceof MozConnection,
+   "navigator.mozConnection is a MozConnection object");
+
+checkInterface("Connection");
+
+ok('bandwidth' in navigator.mozConnection,
+   "bandwidth should be a Connection attribute");
+is(navigator.mozConnection.bandwidth, Infinity,
+   "By default connection.bandwidth is equals to Infinity");
+
+ok('metered' in navigator.mozConnection,
+   "metered should be a Connection attribute");
+is(navigator.mozConnection.metered, false,
+   "By default the connection is not metered");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2502,17 +2502,17 @@ NPError NP_CALLBACK
       else {
         return NPERR_GENERIC_ERROR;
       }
     }
 #endif
 #ifdef MOZ_WIDGET_ANDROID
   case kRequestDrawingModel_ANPSetValue:
     if (inst)
-      inst->SetDrawingModel(NS_PTR_TO_INT32(result));
+      inst->SetANPDrawingModel(NS_PTR_TO_INT32(result));
     return NPERR_NO_ERROR;
   case kAcceptEvents_ANPSetValue:
     return NPERR_NO_ERROR;
 #endif
     default:
       return NPERR_GENERIC_ERROR;
   }
 }
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -84,17 +84,17 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
 #ifdef NP_NO_QUICKDRAW
     mDrawingModel(NPDrawingModelCoreGraphics),
 #else
     mDrawingModel(NPDrawingModelQuickDraw),
 #endif
 #endif
 #ifdef MOZ_WIDGET_ANDROID
     mSurface(nsnull),
-    mDrawingModel(0),
+    mANPDrawingModel(0),
 #endif
     mRunning(NOT_STARTED),
     mWindowless(false),
     mWindowlessLocal(false),
     mTransparent(false),
     mCached(false),
     mUsesDOMForCursor(false),
     mInPluginInitCall(false),
@@ -726,20 +726,21 @@ void nsNPAPIPluginInstance::SetEventMode
     return;
   }
 
   owner->SetEventModel(aModel);
 }
 #endif
 
 #if defined(MOZ_WIDGET_ANDROID)
-void nsNPAPIPluginInstance::SetDrawingModel(PRUint32 aModel)
+void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel)
 {
-  mDrawingModel = aModel;
+  mANPDrawingModel = aModel;
 }
+
 class SurfaceGetter : public nsRunnable {
 public:
   SurfaceGetter(nsNPAPIPluginInstance* aInstance, NPPluginFuncs* aPluginFunctions, NPP_t aNPP) : 
     mInstance(aInstance), mPluginFunctions(aPluginFunctions), mNPP(aNPP) {
   }
   ~SurfaceGetter() {
   }
   nsresult Run() {
@@ -755,17 +756,17 @@ private:
   nsNPAPIPluginInstance* mInstance;
   NPP_t mNPP;
   NPPluginFuncs* mPluginFunctions;
 };
 
 
 void* nsNPAPIPluginInstance::GetJavaSurface()
 {
-  if (mDrawingModel != kSurface_ANPDrawingModel)
+  if (mANPDrawingModel != kSurface_ANPDrawingModel)
     return nsnull;
   
   return mSurface;
 }
 
 void nsNPAPIPluginInstance::SetJavaSurface(void* aSurface)
 {
   mSurface = aSurface;
@@ -780,17 +781,17 @@ void nsNPAPIPluginInstance::RequestJavaS
 
   ((SurfaceGetter*)mSurfaceGetter.get())->RequestSurface();
 }
 
 #endif
 
 nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel)
 {
-#if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
+#if defined(XP_MACOSX)
   *aModel = (PRInt32)mDrawingModel;
   return NS_OK;
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
 nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing)
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -145,17 +145,18 @@ public:
   bool UsesDOMForCursor();
 
 #ifdef XP_MACOSX
   void SetDrawingModel(NPDrawingModel aModel);
   void SetEventModel(NPEventModel aModel);
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
-  void SetDrawingModel(PRUint32 aModel);
+  PRUint32 GetANPDrawingModel() { return mANPDrawingModel; }
+  void SetANPDrawingModel(PRUint32 aModel);
   void* GetJavaSurface();
   void SetJavaSurface(void* aSurface);
   void RequestJavaSurface();
 #endif
 
   nsresult NewStreamListener(const char* aURL, void* notifyData,
                              nsIPluginStreamListener** listener);
 
@@ -224,17 +225,17 @@ protected:
   // the browser.
   NPP_t mNPP;
 
 #ifdef XP_MACOSX
   NPDrawingModel mDrawingModel;
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
-  PRUint32 mDrawingModel;
+  PRUint32 mANPDrawingModel;
   nsCOMPtr<nsIRunnable> mSurfaceGetter;
 #endif
 
   enum {
     NOT_STARTED,
     RUNNING,
     DESTROYING,
     DESTROYED
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2863,18 +2863,17 @@ void nsPluginInstanceOwner::Paint(const 
 
 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
                                   const gfxRect& aFrameRect,
                                   const gfxRect& aDirtyRect)
 {
   if (!mInstance || !mObjectFrame)
     return;
 
-  PRInt32 model;
-  mInstance->GetDrawingModel(&model);
+  PRInt32 model = mInstance->GetANPDrawingModel();
 
   if (model == kSurface_ANPDrawingModel) {
     if (!AddPluginView(aFrameRect)) {
       NPRect rect;
       rect.left = rect.top = 0;
       rect.right = aFrameRect.width;
       rect.bottom = aFrameRect.height;
       InvalidateRect(&rect);
--- a/dom/sms/interfaces/Makefile.in
+++ b/dom/sms/interfaces/Makefile.in
@@ -46,11 +46,15 @@ XPIDL_MODULE = dom_sms
 include $(topsrcdir)/dom/dom-config.mk
 
 XPIDLSRCS = \
   nsIDOMNavigatorSms.idl \
   nsIDOMSmsManager.idl \
   nsISmsService.idl \
   nsIDOMSmsMessage.idl \
   nsIDOMSmsEvent.idl \
+  nsISmsDatabaseService.idl \
+  nsIDOMSmsRequest.idl \
+  nsIDOMSmsFilter.idl \
+  nsIDOMSmsCursor.idl \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsIDOMSmsCursor.idl
@@ -0,0 +1,48 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIDOMMozSmsFilter;
+interface nsIDOMMozSmsMessage;
+
+[scriptable, function, uuid(77b41d7e-ccb1-4480-8322-2af7bc437a3c)]
+interface nsIDOMMozSmsCursor : nsISupports
+{
+  // Can be null if there is no more results.
+  readonly attribute nsIDOMMozSmsMessage message;
+                                    void continue();
+};
--- a/dom/sms/interfaces/nsIDOMSmsEvent.idl
+++ b/dom/sms/interfaces/nsIDOMSmsEvent.idl
@@ -34,13 +34,14 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIDOMEvent.idl"
 
 interface nsIDOMMozSmsMessage;
 
-[scriptable, uuid(34dda4c3-4683-4323-9ee3-2a7bfef7df3b)]
+[scriptable, uuid(fa8d1c86-85b1-4e5b-978c-12dd296cd1cc)]
 interface nsIDOMMozSmsEvent : nsIDOMEvent
 {
+  [binaryname(MessageMoz)]
   readonly attribute nsIDOMMozSmsMessage message;
 };
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsIDOMSmsFilter.idl
@@ -0,0 +1,57 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, builtinclass, uuid(7da08e45-ee81-4293-912b-2f2fea5b6935)]
+interface nsIDOMMozSmsFilter : nsISupports
+{
+  // A date that can return null.
+  [implicit_jscontext]
+  attribute jsval startDate;
+
+  // A date that can return null.
+  [implicit_jscontext]
+  attribute jsval endDate;
+
+  // An array of DOMString that can return null.
+  [implicit_jscontext]
+  attribute jsval numbers;
+
+  // A DOMString that can return and be set to "sent", "received" or null.
+  [Null(Empty)]
+  attribute DOMString delivery;
+};
--- a/dom/sms/interfaces/nsIDOMSmsManager.idl
+++ b/dom/sms/interfaces/nsIDOMSmsManager.idl
@@ -32,17 +32,33 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
+interface nsIDOMMozSmsRequest;
+interface nsIDOMMozSmsFilter;
 
-[scriptable, function, uuid(807d593c-09cb-4aa3-afa5-aa0a671bd0d3)]
+[scriptable, function, uuid(c9916dce-2947-41bb-95c2-818f792a020c)]
 interface nsIDOMMozSmsManager : nsIDOMEventTarget
 {
-  unsigned short getNumberOfMessagesForText(in DOMString text);
-            void send(in DOMString number, in DOMString message);
+  unsigned short      getNumberOfMessagesForText(in DOMString text);
+
+  // The first parameter can be either a DOMString (only one number) or an array
+  // of DOMStrings.
+  // The method returns a SmsRequest object if one number has been passed.
+  // An array of SmsRequest objects otherwise.
+  jsval send(in jsval number, in DOMString message);
+
+  [binaryname(GetMessageMoz)] nsIDOMMozSmsRequest getMessage(in long id);
+
+  // The parameter can be either a message id or a SmsMessage.
+  nsIDOMMozSmsRequest delete(in jsval param);
+
+  nsIDOMMozSmsRequest getMessages(in nsIDOMMozSmsFilter filter, in boolean reverse);
 
   attribute nsIDOMEventListener onreceived;
+  attribute nsIDOMEventListener onsent;
+  attribute nsIDOMEventListener ondelivered;
 };
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsIDOMSmsRequest.idl
@@ -0,0 +1,53 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIDOMEventTarget.idl"
+
+interface nsIDOMEventListener;
+
+[scriptable, function, uuid(1b24469d-cfb7-4667-aaf0-c1d17289ae7c)]
+interface nsIDOMMozSmsRequest : nsIDOMEventTarget
+{
+  // Returns whether "processing" or "done".
+  readonly attribute DOMString           readyState;
+  // Can be null.
+  readonly attribute DOMString           error;
+  // Can be bool, nsIDOMSmsMessage, nsIDOMSmsIterator or null.
+  readonly attribute jsval               result;
+
+           attribute nsIDOMEventListener onsuccess;
+           attribute nsIDOMEventListener onerror;
+};
new file mode 100644
--- /dev/null
+++ b/dom/sms/interfaces/nsISmsDatabaseService.idl
@@ -0,0 +1,60 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+%{C++
+#define SMS_DATABASE_SERVICE_CID \
+{ 0x2454c2a1, 0xefdd, 0x4d96,    \
+{ 0x83, 0xbd, 0x51, 0xa2, 0x9a, 0x21, 0xf5, 0xab } }
+#define SMS_DATABASE_SERVICE_CONTRACTID "@mozilla.org/sms/smsdatabaseservice;1"
+%}
+
+interface nsIDOMMozSmsFilter;
+
+[scriptable, function, uuid(3ddf7dc3-626c-47ee-8b41-3f55d5af49c9)]
+interface nsISmsDatabaseService : nsISupports
+{
+  // Takes some information required to save the message and returns its id.
+  long saveSentMessage(in DOMString aReceiver, in DOMString aBody, in unsigned long long aDate);
+
+  [binaryname(GetMessageMoz)] void getMessage(in long messageId, in long requestId, [optional] in unsigned long long processId);
+  void deleteMessage(in long messageId, in long requestId, [optional] in unsigned long long processId);
+
+  void createMessageList(in nsIDOMMozSmsFilter filter, in boolean reverse, in long requestId, [optional] in unsigned long long processId);
+  void getNextMessageInList(in long listId, in long requestId, in unsigned long long processId);
+  void clearMessageList(in long listId);
+};
--- a/dom/sms/interfaces/nsISmsService.idl
+++ b/dom/sms/interfaces/nsISmsService.idl
@@ -35,26 +35,27 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIDOMMozSmsMessage;
 
 %{C++
-#define NS_SMSSERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
-#define SMSSERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
+#define SMS_SERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
+#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
 %}
 
 [scriptable, builtinclass, uuid(a0fbbe74-5d61-4b7e-b7ab-9b5224f9e5e9)]
 interface nsISmsService : nsISupports
 {
   boolean        hasSupport();
   unsigned short getNumberOfMessagesForText(in DOMString text);
-            void send(in DOMString number, in DOMString message);
+            void send(in DOMString number, in DOMString message,
+                      in long requestId, [optional] in unsigned long long processId);
 
   [implicit_jscontext]
   nsIDOMMozSmsMessage createSmsMessage(in long      id,
                                        in DOMString delivery,
                                        in DOMString sender,
                                        in DOMString receiver,
                                        in DOMString body,
                                        in jsval     timestamp);
--- a/dom/sms/src/Constants.cpp
+++ b/dom/sms/src/Constants.cpp
@@ -34,13 +34,15 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
-const char* kSmsReceivedObserverTopic = "sms-received";
+const char* kSmsReceivedObserverTopic  = "sms-received";
+const char* kSmsSentObserverTopic      = "sms-sent";
+const char* kSmsDeliveredObserverTopic = "sms-delivered";
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/Constants.h
+++ b/dom/sms/src/Constants.h
@@ -37,17 +37,19 @@
 
 #ifndef mozilla_dom_sms_Constants_h
 #define mozilla_dom_sms_Constants_h
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
-extern const char* kSmsReceivedObserverTopic; // Defined in the .cpp.
+extern const char* kSmsReceivedObserverTopic;  // Defined in the .cpp.
+extern const char* kSmsSentObserverTopic;      // Defined in the .cpp.
+extern const char* kSmsDeliveredObserverTopic; // Defined in the .cpp.
 
 #define DELIVERY_RECEIVED NS_LITERAL_STRING("received")
 #define DELIVERY_SENT     NS_LITERAL_STRING("sent")
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/sms/src/Makefile.in
+++ b/dom/sms/src/Makefile.in
@@ -58,36 +58,44 @@ FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 EXPORTS_NAMESPACES = mozilla/dom/sms
 
 EXPORTS_mozilla/dom/sms = \
   SmsChild.h \
   SmsParent.h \
-  SmsServiceFactory.h \
+  SmsServicesFactory.h \
   Constants.h \
   Types.h \
   SmsMessage.h \
+  SmsRequestManager.h \
+  SmsRequest.h \
   $(NULL)
 
 CPPSRCS = \
   SmsManager.cpp \
   SmsService.cpp \
   SmsIPCService.cpp \
-  SmsServiceFactory.cpp \
+  SmsServicesFactory.cpp \
   SmsParent.cpp \
   SmsMessage.cpp \
   SmsEvent.cpp \
   Constants.cpp \
   SmsChild.cpp \
+  SmsDatabaseService.cpp \
+  SmsRequest.cpp \
+  SmsRequestManager.cpp \
+  SmsFilter.cpp \
+  SmsCursor.cpp \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/content/events/src \
+  -I$(topsrcdir)/dom/base \
   $(NULL)
 
 # Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
 # subdirectory (and the ipc one).
 LOCAL_INCLUDES += $(VPATH:%=-I%)
 
 ifdef MOZ_B2G_RIL
 LOCAL_INCLUDES += \
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsCursor.cpp
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SmsCursor.h"
+#include "nsIDOMClassInfo.h"
+#include "nsDOMError.h"
+#include "nsIDOMSmsMessage.h"
+#include "nsIDOMSmsRequest.h"
+#include "SmsRequest.h"
+#include "SmsRequestManager.h"
+#include "nsISmsDatabaseService.h"
+
+DOMCI_DATA(MozSmsCursor, mozilla::dom::sms::SmsCursor)
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SmsCursor)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsCursor)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsCursor)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_2(SmsCursor, mRequest, mMessage)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(SmsCursor)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(SmsCursor)
+
+SmsCursor::SmsCursor()
+  : mListId(-1)
+{
+}
+
+SmsCursor::SmsCursor(PRInt32 aListId, nsIDOMMozSmsRequest* aRequest)
+  : mListId(aListId)
+  , mRequest(aRequest)
+{
+}
+
+SmsCursor::~SmsCursor()
+{
+  NS_ASSERTION(!mMessage, "mMessage shouldn't be set!");
+
+  if (mListId != -1) {
+    nsCOMPtr<nsISmsDatabaseService> smsDBService =
+      do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+
+    if (!smsDBService) {
+      NS_ERROR("Can't find SmsDBService!");
+    }
+
+    smsDBService->ClearMessageList(mListId);
+  }
+}
+
+void
+SmsCursor::Disconnect()
+{
+  NS_ASSERTION(!mMessage, "mMessage shouldn't be set!");
+
+  mRequest = nsnull;
+  mListId = -1;
+}
+
+NS_IMETHODIMP
+SmsCursor::GetMessage(nsIDOMMozSmsMessage** aMessage)
+{
+  NS_IF_ADDREF(*aMessage = mMessage);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsCursor::Continue()
+{
+  // No message means we are waiting for a message or we got the last one.
+  if (!mMessage) {
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  mMessage = nsnull;
+  static_cast<SmsRequest*>(mRequest.get())->Reset();
+
+  PRInt32 requestId = SmsRequestManager::GetInstance()->AddRequest(mRequest);
+
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+  smsDBService->GetNextMessageInList(mListId, requestId, 0);
+
+  return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsCursor.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_sms_SmsCursor_h
+#define mozilla_dom_sms_SmsCursor_h
+
+#include "nsIDOMSmsCursor.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+
+class nsIDOMMozSmsMessage;
+class nsIDOMMozSmsRequest;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsCursor : public nsIDOMMozSmsCursor
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIDOMMOZSMSCURSOR
+
+  NS_DECL_CYCLE_COLLECTION_CLASS(SmsCursor)
+
+  SmsCursor();
+  SmsCursor(PRInt32 aListId, nsIDOMMozSmsRequest* aRequest);
+
+  ~SmsCursor();
+
+  void SetMessage(nsIDOMMozSmsMessage* aMessage);
+
+  void Disconnect();
+
+private:
+  PRInt32                       mListId;
+  nsCOMPtr<nsIDOMMozSmsRequest> mRequest;
+  nsCOMPtr<nsIDOMMozSmsMessage> mMessage;
+};
+
+inline void
+SmsCursor::SetMessage(nsIDOMMozSmsMessage* aMessage)
+{
+  mMessage = aMessage;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsCursor_h
--- a/dom/sms/src/SmsEvent.cpp
+++ b/dom/sms/src/SmsEvent.cpp
@@ -72,17 +72,17 @@ SmsEvent::Init(const nsAString& aEventTy
                                       aCancelableArg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mMessage = aMessage;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsEvent::GetMessage(nsIDOMMozSmsMessage** aMessage)
+SmsEvent::GetMessageMoz(nsIDOMMozSmsMessage** aMessage)
 {
   NS_IF_ADDREF(*aMessage = mMessage);
   return NS_OK;
 }
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsFilter.cpp
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SmsFilter.h"
+#include "nsIDOMClassInfo.h"
+#include "Constants.h"
+#include "nsError.h"
+#include "Constants.h"
+#include "jsapi.h"
+#include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch.
+#include "js/Utility.h"
+#include "nsJSUtils.h"
+#include "nsDOMString.h"
+
+DOMCI_DATA(MozSmsFilter, mozilla::dom::sms::SmsFilter)
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_INTERFACE_MAP_BEGIN(SmsFilter)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsFilter)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsFilter)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(SmsFilter)
+NS_IMPL_RELEASE(SmsFilter)
+
+SmsFilter::SmsFilter()
+{
+  mData.startDate() = 0;
+  mData.endDate() = 0;
+  mData.delivery() = eDeliveryState_Unknown;
+}
+
+SmsFilter::SmsFilter(const SmsFilterData& aData)
+  : mData(aData)
+{
+}
+
+/* static */ nsresult
+SmsFilter::NewSmsFilter(nsISupports** aSmsFilter)
+{
+  NS_ADDREF(*aSmsFilter = new SmsFilter());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetStartDate(JSContext* aCx, jsval* aStartDate)
+{
+  if (mData.startDate() == 0) {
+    *aStartDate = JSVAL_NULL;
+    return NS_OK;
+  }
+
+  aStartDate->setObjectOrNull(JS_NewDateObjectMsec(aCx, mData.startDate()));
+  NS_ENSURE_TRUE(aStartDate->isObject(), NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetStartDate(JSContext* aCx, const jsval& aStartDate)
+{
+  if (aStartDate == JSVAL_NULL) {
+    mData.startDate() = 0;
+    return NS_OK;
+  }
+
+  if (!aStartDate.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  JSObject& obj = aStartDate.toObject();
+  if (!JS_ObjectIsDate(aCx, &obj)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mData.startDate() = js_DateGetMsecSinceEpoch(aCx, &obj);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetEndDate(JSContext* aCx, jsval* aEndDate)
+{
+  if (mData.endDate() == 0) {
+    *aEndDate = JSVAL_NULL;
+    return NS_OK;
+  }
+
+  aEndDate->setObjectOrNull(JS_NewDateObjectMsec(aCx, mData.endDate()));
+  NS_ENSURE_TRUE(aEndDate->isObject(), NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetEndDate(JSContext* aCx, const jsval& aEndDate)
+{
+  if (aEndDate == JSVAL_NULL) {
+    mData.endDate() = 0;
+    return NS_OK;
+  }
+
+  if (!aEndDate.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  JSObject& obj = aEndDate.toObject();
+  if (!JS_ObjectIsDate(aCx, &obj)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mData.endDate() = js_DateGetMsecSinceEpoch(aCx, &obj);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetNumbers(JSContext* aCx, jsval* aNumbers)
+{
+  PRUint32 length = mData.numbers().Length();
+
+  if (length == 0) {
+    *aNumbers = JSVAL_NULL;
+    return NS_OK;
+  }
+
+  jsval* numbers = new jsval[length];
+
+  for (PRUint32 i=0; i<length; ++i) {
+    numbers[i].setString(JS_NewUCStringCopyN(aCx, mData.numbers()[i].get(),
+                                             mData.numbers()[i].Length()));
+  }
+
+  aNumbers->setObjectOrNull(JS_NewArrayObject(aCx, length, numbers));
+  NS_ENSURE_TRUE(aNumbers->isObject(), NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetNumbers(JSContext* aCx, const jsval& aNumbers)
+{
+  if (aNumbers == JSVAL_NULL) {
+    mData.numbers().Clear();
+    return NS_OK;
+  }
+
+  if (!aNumbers.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  JSObject& obj = aNumbers.toObject();
+  if (!JS_IsArrayObject(aCx, &obj)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  jsuint size;
+  JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, &obj, &size));
+
+  nsTArray<nsString> numbers;
+
+  for (jsuint i=0; i<size; ++i) {
+    jsval jsNumber;
+    if (!JS_GetElement(aCx, &obj, i, &jsNumber)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    if (!jsNumber.isString()) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    nsDependentJSString number;
+    number.init(aCx, jsNumber.toString());
+
+    numbers.AppendElement(number);
+  }
+
+  mData.numbers().Clear();
+  mData.numbers().AppendElements(numbers);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::GetDelivery(nsAString& aDelivery)
+{
+  switch (mData.delivery()) {
+    case eDeliveryState_Received:
+      aDelivery = DELIVERY_RECEIVED;
+      break;
+    case eDeliveryState_Sent:
+      aDelivery = DELIVERY_SENT;
+      break;
+    case eDeliveryState_Unknown:
+      SetDOMStringToNull(aDelivery);
+      break;
+    default:
+      NS_ASSERTION(false, "We shouldn't get another delivery state!");
+      return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsFilter::SetDelivery(const nsAString& aDelivery)
+{
+  if (aDelivery.IsEmpty()) {
+    mData.delivery() = eDeliveryState_Unknown;
+    return NS_OK;
+  }
+
+  if (aDelivery.Equals(DELIVERY_RECEIVED)) {
+    mData.delivery() = eDeliveryState_Received;
+    return NS_OK;
+  }
+
+  if (aDelivery.Equals(DELIVERY_SENT)) {
+    mData.delivery() = eDeliveryState_Sent;
+    return NS_OK;
+  }
+
+  return NS_ERROR_INVALID_ARG;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsFilter.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_sms_SmsFilter_h
+#define mozilla_dom_sms_SmsFilter_h
+
+#include "mozilla/dom/sms/PSms.h"
+#include "nsIDOMSmsFilter.h"
+#include "Types.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsFilter : public nsIDOMMozSmsFilter
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMMOZSMSFILTER
+
+  SmsFilter();
+  SmsFilter(const SmsFilterData& aData);
+
+  const SmsFilterData& GetData() const;
+
+  static nsresult NewSmsFilter(nsISupports** aSmsFilter);
+
+private:
+  SmsFilterData mData;
+};
+
+inline const SmsFilterData&
+SmsFilter::GetData() const {
+  return mData;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsFilter_h
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -30,47 +30,60 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "SmsFilter.h"
 #include "SmsManager.h"
 #include "nsIDOMClassInfo.h"
 #include "nsISmsService.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "Constants.h"
 #include "SmsEvent.h"
 #include "nsIDOMSmsMessage.h"
+#include "nsIDOMSmsRequest.h"
+#include "SmsRequestManager.h"
+#include "nsJSUtils.h"
+#include "nsContentUtils.h"
+#include "nsISmsDatabaseService.h"
+#include "nsIXPConnect.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
-#define RECEIVED_EVENT_NAME NS_LITERAL_STRING("received")
+#define RECEIVED_EVENT_NAME  NS_LITERAL_STRING("received")
+#define SENT_EVENT_NAME      NS_LITERAL_STRING("sent")
+#define DELIVERED_EVENT_NAME NS_LITERAL_STRING("delivered")
 
 DOMCI_DATA(MozSmsManager, mozilla::dom::sms::SmsManager)
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SmsManager)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SmsManager,
                                                   nsDOMEventTargetWrapperCache)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(received)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(sent)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(delivered)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SmsManager,
                                                 nsDOMEventTargetWrapperCache)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(received)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(sent)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(delivered)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SmsManager)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsManager)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozSmsManager)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
 
@@ -86,53 +99,205 @@ SmsManager::Init(nsPIDOMWindow *aWindow,
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   // GetObserverService() can return null is some situations like shutdown.
   if (!obs) {
     return;
   }
 
   obs->AddObserver(this, kSmsReceivedObserverTopic, false);
+  obs->AddObserver(this, kSmsSentObserverTopic, false);
+  obs->AddObserver(this, kSmsDeliveredObserverTopic, false);
 }
 
 void
 SmsManager::Shutdown()
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   // GetObserverService() can return null is some situations like shutdown.
   if (!obs) {
     return;
   }
 
   obs->RemoveObserver(this, kSmsReceivedObserverTopic);
+  obs->RemoveObserver(this, kSmsSentObserverTopic);
+  obs->RemoveObserver(this, kSmsDeliveredObserverTopic);
 }
 
 NS_IMETHODIMP
 SmsManager::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
 {
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, NS_OK);
 
   smsService->GetNumberOfMessagesForText(aText, aResult);
 
   return NS_OK;
 }
 
+nsresult
+SmsManager::Send(JSContext* aCx, JSObject* aGlobal, JSString* aNumber,
+                 const nsAString& aMessage, jsval* aRequest)
+{
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
+  if (!smsService) {
+    NS_ERROR("No SMS Service!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsRequest> request;
+
+  int requestId =
+    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext,
+                                                    getter_AddRefs(request));
+  NS_ASSERTION(request, "The request object must have been created!");
+
+  nsDependentJSString number;
+  number.init(aCx, aNumber);
+
+  smsService->Send(number, aMessage, requestId, 0);
+
+  nsresult rv = nsContentUtils::WrapNative(aCx, aGlobal, request, aRequest);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to create the js value!");
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP
-SmsManager::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsManager::Send(const jsval& aNumber, const nsAString& aMessage, jsval* aReturn)
 {
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(smsService, NS_OK);
+  JSContext* cx = mScriptContext->GetNativeContext();
+  NS_ASSERTION(cx, "Failed to get a context!");
+
+  if (!aNumber.isString() &&
+      !(aNumber.isObject() && JS_IsArrayObject(cx, &aNumber.toObject()))) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  JSObject* global = mScriptContext->GetNativeGlobal();
+  NS_ASSERTION(global, "Failed to get global object!");
+
+  JSAutoRequest ar(cx);
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, global)) {
+    NS_ERROR("Failed to enter the js compartment!");
+    return NS_ERROR_FAILURE;
+  }
+
+  if (aNumber.isString()) {
+    return Send(cx, global, aNumber.toString(), aMessage, aReturn);
+  }
+
+  // Must be an array then.
+  JSObject& numbers = aNumber.toObject();
+
+  jsuint size;
+  JS_ALWAYS_TRUE(JS_GetArrayLength(cx, &numbers, &size));
+
+  jsval* requests = new jsval[size];
+
+  for (jsuint i=0; i<size; ++i) {
+    jsval number;
+    if (!JS_GetElement(cx, &numbers, i, &number)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    nsresult rv = Send(cx, global, number.toString(), aMessage, &requests[i]);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  aReturn->setObjectOrNull(JS_NewArrayObject(cx, size, requests));
+  NS_ENSURE_TRUE(aReturn->isObject(), NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsManager::GetMessageMoz(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
+{
+  int requestId =
+    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
+  NS_ASSERTION(*aRequest, "The request object must have been created!");
+
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+  smsDBService->GetMessageMoz(aId, requestId, 0);
 
-  smsService->Send(aNumber, aMessage);
+  return NS_OK;
+}
+
+nsresult
+SmsManager::Delete(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
+{
+  int requestId =
+    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
+  NS_ASSERTION(*aRequest, "The request object must have been created!");
+
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+  smsDBService->DeleteMessage(aId, requestId, 0);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsManager::Delete(const jsval& aParam, nsIDOMMozSmsRequest** aRequest)
+{
+  if (aParam.isInt32()) {
+    return Delete(aParam.toInt32(), aRequest);
+  }
+
+  if (!aParam.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message =
+    do_QueryInterface(nsContentUtils::XPConnect()->GetNativeOfWrapper(
+          mScriptContext->GetNativeContext(), &aParam.toObject()));
+  NS_ENSURE_TRUE(message, NS_ERROR_INVALID_ARG);
+
+  PRInt32 id;
+  message->GetId(&id);
+
+  return Delete(id, aRequest);
+}
+
+NS_IMETHODIMP
+SmsManager::GetMessages(nsIDOMMozSmsFilter* aFilter, bool aReverse,
+                        nsIDOMMozSmsRequest** aRequest)
+{
+  nsCOMPtr<nsIDOMMozSmsFilter> filter = aFilter;
+
+  if (!filter) {
+    filter = new SmsFilter();
+  }
+
+  int requestId =
+    SmsRequestManager::GetInstance()->CreateRequest(mOwner, mScriptContext, aRequest);
+  NS_ASSERTION(*aRequest, "The request object must have been created!");
+
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
+
+  smsDBService->CreateMessageList(filter, aReverse, requestId, 0);
 
   return NS_OK;
 }
 
 NS_IMPL_EVENT_HANDLER(SmsManager, received)
+NS_IMPL_EVENT_HANDLER(SmsManager, sent)
+NS_IMPL_EVENT_HANDLER(SmsManager, delivered)
 
 nsresult
 SmsManager::DispatchTrustedSmsEventToSelf(const nsAString& aEventName, nsIDOMMozSmsMessage* aMessage)
 {
   nsRefPtr<nsDOMEvent> event = new SmsEvent(nsnull, nsnull);
   nsresult rv = static_cast<SmsEvent*>(event.get())->Init(aEventName, false,
                                                           false, aMessage);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -154,16 +319,39 @@ SmsManager::Observe(nsISupports* aSubjec
   if (!strcmp(aTopic, kSmsReceivedObserverTopic)) {
     nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
     if (!message) {
       NS_ERROR("Got a 'sms-received' topic without a valid message!");
       return NS_OK;
     }
 
     DispatchTrustedSmsEventToSelf(RECEIVED_EVENT_NAME, message);
+    return NS_OK;
+  }
+
+  if (!strcmp(aTopic, kSmsSentObserverTopic)) {
+    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+    if (!message) {
+      NS_ERROR("Got a 'sms-sent' topic without a valid message!");
+      return NS_OK;
+    }
+
+    DispatchTrustedSmsEventToSelf(SENT_EVENT_NAME, message);
+    return NS_OK;
+  }
+
+  if (!strcmp(aTopic, kSmsDeliveredObserverTopic)) {
+    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+    if (!message) {
+      NS_ERROR("Got a 'sms-delivered' topic without a valid message!");
+      return NS_OK;
+    }
+
+    DispatchTrustedSmsEventToSelf(DELIVERED_EVENT_NAME, message);
+    return NS_OK;
   }
 
   return NS_OK;
 }
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/SmsManager.h
+++ b/dom/sms/src/SmsManager.h
@@ -61,18 +61,31 @@ public:
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SmsManager,
                                            nsDOMEventTargetWrapperCache)
 
   void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
   void Shutdown();
 
 private:
+  /**
+   * Internal Send() method used to send one message.
+   */
+  nsresult Send(JSContext* aCx, JSObject* aGlobal, JSString* aNumber,
+                const nsAString& aMessage, jsval* aRequest);
+
+  /**
+   * Internal Delete() method used to delete a message.
+   */
+  nsresult Delete(PRInt32 aId, nsIDOMMozSmsRequest** aRequest);
+
   nsresult DispatchTrustedSmsEventToSelf(const nsAString& aEventName,
                                          nsIDOMMozSmsMessage* aMessage);
   NS_DECL_EVENT_HANDLER(received)
+  NS_DECL_EVENT_HANDLER(sent)
+  NS_DECL_EVENT_HANDLER(delivered)
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_sms_SmsManager_h
--- a/dom/sms/src/SmsMessage.cpp
+++ b/dom/sms/src/SmsMessage.cpp
@@ -52,16 +52,23 @@ NS_INTERFACE_MAP_BEGIN(SmsMessage)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsMessage)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsMessage)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(SmsMessage)
 NS_IMPL_RELEASE(SmsMessage)
 
+SmsMessage::SmsMessage(PRInt32 aId, DeliveryState aDelivery,
+                       const nsString& aSender, const nsString& aReceiver,
+                       const nsString& aBody, PRUint64 aTimestamp)
+  : mData(aId, aDelivery, aSender, aReceiver, aBody, aTimestamp)
+{
+}
+
 SmsMessage::SmsMessage(const SmsMessageData& aData)
   : mData(aData)
 {
 }
 
 /* static */ nsresult
 SmsMessage::Create(PRInt32 aId,
                    const nsAString& aDelivery,
@@ -126,24 +133,25 @@ SmsMessage::GetId(PRInt32* aId)
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsMessage::GetDelivery(nsAString& aDelivery)
 {
   switch (mData.delivery()) {
     case eDeliveryState_Received:
-      aDelivery.AssignLiteral("received");
+      aDelivery = DELIVERY_RECEIVED;
       break;
     case eDeliveryState_Sent:
-      aDelivery.AssignLiteral("sent");
+      aDelivery = DELIVERY_SENT;
       break;
     case eDeliveryState_Unknown:
+    case eDeliveryState_EndGuard:
     default:
-      NS_ASSERTION(true, "We shouldn't get an unknown delivery state!");
+      NS_ASSERTION(true, "We shouldn't get any other delivery state!");
       return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsMessage::GetSender(nsAString& aSender)
--- a/dom/sms/src/SmsMessage.h
+++ b/dom/sms/src/SmsMessage.h
@@ -37,27 +37,31 @@
 
 #ifndef mozilla_dom_sms_SmsMessage_h
 #define mozilla_dom_sms_SmsMessage_h
 
 #include "mozilla/dom/sms/PSms.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsString.h"
 #include "jspubtd.h"
+#include "Types.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 class SmsMessage : public nsIDOMMozSmsMessage
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZSMSMESSAGE
 
+  SmsMessage(PRInt32 aId, DeliveryState aDelivery, const nsString& aSender,
+             const nsString& aReceiver, const nsString& aBody,
+             PRUint64 aTimestamp);
   SmsMessage(const SmsMessageData& aData);
 
   static nsresult Create(PRInt32 aId,
                          const nsAString& aDelivery,
                          const nsAString& aSender,
                          const nsAString& aReceiver,
                          const nsAString& aBody,
                          const JS::Value& aTimestamp,
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequest.cpp
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SmsRequest.h"
+#include "nsIDOMClassInfo.h"
+#include "nsDOMString.h"
+#include "nsContentUtils.h"
+#include "nsIDOMSmsMessage.h"
+#include "nsIDOMSmsCursor.h"
+
+DOMCI_DATA(MozSmsRequest, mozilla::dom::sms::SmsRequest)
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(SmsRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SmsRequest,
+                                                  nsDOMEventTargetWrapperCache)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCursor)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SmsRequest,
+                                                nsDOMEventTargetWrapperCache)
+  if (tmp->mResultRooted) {
+    tmp->mResult = JSVAL_VOID;
+    tmp->UnrootResult();
+  }
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCursor)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(SmsRequest,
+                                               nsDOMEventTargetWrapperCache)
+  if (JSVAL_IS_GCTHING(tmp->mResult)) {
+    void *gcThing = JSVAL_TO_GCTHING(tmp->mResult);
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResult")
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SmsRequest)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozSmsRequest)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozSmsRequest)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsRequest)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+
+NS_IMPL_ADDREF_INHERITED(SmsRequest, nsDOMEventTargetWrapperCache)
+NS_IMPL_RELEASE_INHERITED(SmsRequest, nsDOMEventTargetWrapperCache)
+
+NS_IMPL_EVENT_HANDLER(SmsRequest, success)
+NS_IMPL_EVENT_HANDLER(SmsRequest, error)
+
+SmsRequest::SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext)
+  : mResult(JSVAL_VOID)
+  , mResultRooted(false)
+  , mError(eNoError)
+  , mDone(false)
+{
+  // Those vars come from nsDOMEventTargetHelper.
+  mOwner = aWindow;
+  mScriptContext = aScriptContext;
+}
+
+SmsRequest::~SmsRequest()
+{
+  if (mResultRooted) {
+    UnrootResult();
+  }
+}
+
+void
+SmsRequest::Reset()
+{
+  NS_ASSERTION(mDone, "mDone should be true if we try to reset!");
+  NS_ASSERTION(mResult != JSVAL_VOID, "mResult should be set if we try to reset!");
+  NS_ASSERTION(mError == eNoError, "There should be no error if we try to reset!");
+
+  if (mResultRooted) {
+    UnrootResult();
+  }
+
+  mResult = JSVAL_VOID;
+  mDone = false;
+}
+
+void
+SmsRequest::RootResult()
+{
+  NS_ASSERTION(!mResultRooted, "Don't call RootResult() if already rooted!");
+  NS_HOLD_JS_OBJECTS(this, SmsRequest);
+  mResultRooted = true;
+}
+
+void
+SmsRequest::UnrootResult()
+{
+  NS_ASSERTION(mResultRooted, "Don't call UnrotResult() if not rooted!");
+  NS_DROP_JS_OBJECTS(this, SmsRequest);
+  mResultRooted = false;
+}
+
+void
+SmsRequest::SetSuccess(nsIDOMMozSmsMessage* aMessage)
+{
+  SetSuccessInternal(aMessage);
+}
+
+void
+SmsRequest::SetSuccess(bool aResult)
+{
+  NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
+  NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+  NS_PRECONDITION(mResult == JSVAL_NULL, "mResult shouldn't have been set!");
+
+  mResult.setBoolean(aResult);
+  mDone = true;
+}
+
+void
+SmsRequest::SetSuccess(nsIDOMMozSmsCursor* aCursor)
+{
+  if (!SetSuccessInternal(aCursor)) {
+    return;
+  }
+
+  NS_ASSERTION(!mCursor || mCursor == aCursor,
+               "SmsRequest can't change it's cursor!");
+
+  if (!mCursor) {
+    mCursor = aCursor;
+  }
+}
+
+bool
+SmsRequest::SetSuccessInternal(nsISupports* aObject)
+{
+  NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
+  NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+  NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
+
+  JSContext* cx = mScriptContext->GetNativeContext();
+  NS_ASSERTION(cx, "Failed to get a context!");
+
+  JSObject* global = mScriptContext->GetNativeGlobal();
+  NS_ASSERTION(global, "Failed to get global object!");
+
+  JSAutoRequest ar(cx);
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, global)) {
+    SetError(eInternalError);
+    return false;
+  }
+
+  RootResult();
+
+  if (NS_FAILED(nsContentUtils::WrapNative(cx, global, aObject, &mResult))) {
+    UnrootResult();
+    mResult = JSVAL_VOID;
+    SetError(eInternalError);
+    return false;
+  }
+
+  mDone = true;
+  return true;
+}
+
+void
+SmsRequest::SetError(ErrorType aError)
+{
+  NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
+  NS_PRECONDITION(mError == eNoError, "mError shouldn't have been set!");
+  NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
+
+  mDone = true;
+  mError = aError;
+  mCursor = nsnull;
+}
+
+NS_IMETHODIMP
+SmsRequest::GetReadyState(nsAString& aReadyState)
+{
+  if (mDone) {
+    aReadyState.AssignLiteral("done");
+  } else {
+    aReadyState.AssignLiteral("processing");
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsRequest::GetError(nsAString& aError)
+{
+  if (!mDone) {
+    NS_ASSERTION(mError == eNoError,
+                 "There should be no error if the request is still processing!");
+
+    SetDOMStringToNull(aError);
+    return NS_OK;
+  }
+
+  NS_ASSERTION(mError == eNoError || mResult == JSVAL_VOID,
+               "mResult should be void when there is an error!");
+
+  switch (mError) {
+    case eNoError:
+      SetDOMStringToNull(aError);
+      break;
+    case eNoSignalError:
+      aError.AssignLiteral("NoSignalError");
+      break;
+    case eNotFoundError:
+      aError.AssignLiteral("NotFoundError");
+      break;
+    case eUnknownError:
+      aError.AssignLiteral("UnknownError");
+      break;
+    case eInternalError:
+      aError.AssignLiteral("InternalError");
+      break;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsRequest::GetResult(jsval* aResult)
+{
+  if (!mDone) {
+    NS_ASSERTION(mResult == JSVAL_VOID,
+                 "When not done, result should be null!");
+
+    *aResult = JSVAL_VOID;
+    return NS_OK;
+  }
+
+  *aResult = mResult;
+  return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequest.h
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_sms_SmsRequest_h
+#define mozilla_dom_sms_SmsRequest_h
+
+#include "nsIDOMSmsRequest.h"
+#include "nsDOMEventTargetWrapperCache.h"
+
+class nsIDOMMozSmsMessage;
+class nsIDOMMozSmsCursor;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsRequest : public nsIDOMMozSmsRequest
+                 , public nsDOMEventTargetWrapperCache
+{
+public:
+  friend class SmsRequestManager;
+
+  /**
+   * All SMS related errors that could apply to SmsRequest objects.
+   * Make sure to keep this list in sync with the list in:
+   * embedding/android/GeckoSmsManager.java
+   */
+  enum ErrorType {
+    eNoError = 0,
+    eNoSignalError,
+    eNotFoundError,
+    eUnknownError,
+    eInternalError,
+  };
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMMOZSMSREQUEST
+
+  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
+
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(SmsRequest,
+                                                         nsDOMEventTargetWrapperCache)
+
+  void Reset();
+
+private:
+  SmsRequest() MOZ_DELETE;
+
+  SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext);
+  ~SmsRequest();
+
+  /**
+   * Root mResult (jsval) to prevent garbage collection.
+   */
+  void RootResult();
+
+  /**
+   * Unroot mResult (jsval) to allow garbage collection.
+   */
+  void UnrootResult();
+
+  /**
+   * Set the object in a success state with the result being aMessage.
+   */
+  void SetSuccess(nsIDOMMozSmsMessage* aMessage);
+
+  /**
+   * Set the object in a success state with the result being a boolean.
+   */
+  void SetSuccess(bool aResult);
+
+  /**
+   * Set the object in a success state with the result being a SmsCursor.
+   */
+  void SetSuccess(nsIDOMMozSmsCursor* aCursor);
+
+  /**
+   * Set the object in an error state with the error type being aError.
+   */
+  void SetError(ErrorType aError);
+
+  /**
+   * Set the object in a success state with the result being the nsISupports
+   * object in parameter.
+   * @return whether setting the object was a success
+   */
+  bool SetSuccessInternal(nsISupports* aObject);
+
+  /**
+   * Return the internal cursor that is saved when
+   * SetSuccess(nsIDOMMozSmsCursor*) is used.
+   * Returns null if this request isn't associated to an cursor.
+   */
+  nsIDOMMozSmsCursor* GetCursor();
+
+  jsval     mResult;
+  bool      mResultRooted;
+  ErrorType mError;
+  bool      mDone;
+  nsCOMPtr<nsIDOMMozSmsCursor> mCursor;
+
+  NS_DECL_EVENT_HANDLER(success)
+  NS_DECL_EVENT_HANDLER(error)
+};
+
+inline nsIDOMMozSmsCursor*
+SmsRequest::GetCursor()
+{
+  return mCursor;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsRequest_h
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequestManager.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SmsRequestManager.h"
+#include "nsIDOMSmsMessage.h"
+#include "nsDOMEvent.h"
+#include "SmsCursor.h"
+
+/**
+ * We have to use macros here because our leak analysis tool things we are
+ * leaking strings when we have |static const nsString|. Sad :(
+ */
+#define SUCCESS_EVENT_NAME NS_LITERAL_STRING("success")
+#define ERROR_EVENT_NAME   NS_LITERAL_STRING("error")
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+SmsRequestManager* SmsRequestManager::sInstance = nsnull;
+
+void
+SmsRequestManager::Init()
+{
+  NS_PRECONDITION(!sInstance,
+                  "sInstance shouldn't be set. Did you call Init() twice?");
+  sInstance = new SmsRequestManager();
+}
+
+void
+SmsRequestManager::Shutdown()
+{
+  NS_PRECONDITION(sInstance, "sInstance should be set. Did you call Init()?");
+
+  delete sInstance;
+  sInstance = nsnull;
+}
+
+/* static */ SmsRequestManager*
+SmsRequestManager::GetInstance()
+{
+  return sInstance;
+}
+
+PRInt32
+SmsRequestManager::AddRequest(nsIDOMMozSmsRequest* aRequest)
+{
+  // TODO: merge with CreateRequest
+  PRInt32 size = mRequests.Count();
+
+  // Look for empty slots.
+  for (PRInt32 i=0; i<size; ++i) {
+    if (mRequests[i]) {
+      continue;
+    }
+
+    mRequests.ReplaceObjectAt(aRequest, i);
+    return i;
+  }
+
+  mRequests.AppendObject(aRequest);
+  return size;
+}
+
+PRInt32
+SmsRequestManager::CreateRequest(nsPIDOMWindow* aWindow,
+                                 nsIScriptContext* aScriptContext,
+                                 nsIDOMMozSmsRequest** aRequest)
+{
+  nsCOMPtr<nsIDOMMozSmsRequest> request =
+    new SmsRequest(aWindow, aScriptContext);
+
+  PRInt32 size = mRequests.Count();
+
+  // Look for empty slots.
+  for (PRInt32 i=0; i<size; ++i) {
+    if (mRequests[i]) {
+      continue;
+    }
+
+    mRequests.ReplaceObjectAt(request, i);
+    NS_ADDREF(*aRequest = request);
+    return i;
+  }
+
+  mRequests.AppendObject(request);
+  NS_ADDREF(*aRequest = request);
+  return size;
+}
+
+nsresult
+SmsRequestManager::DispatchTrustedEventToRequest(const nsAString& aEventName,
+                                                 nsIDOMMozSmsRequest* aRequest)
+{
+  nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
+  nsresult rv = event->InitEvent(aEventName, false, false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = event->SetTrusted(PR_TRUE);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool dummy;
+  return aRequest->DispatchEvent(event, &dummy);
+}
+
+SmsRequest*
+SmsRequestManager::GetRequest(PRInt32 aRequestId)
+{
+  NS_ASSERTION(mRequests.Count() > aRequestId && mRequests[aRequestId],
+               "Got an invalid request id or it has been already deleted!");
+
+  // It's safe to use the static_cast here given that we did call
+  // |new SmsRequest()|.
+  return static_cast<SmsRequest*>(mRequests[aRequestId]);
+}
+
+template <class T>
+void
+SmsRequestManager::NotifySuccess(PRInt32 aRequestId, T aParam)
+{
+  SmsRequest* request = GetRequest(aRequestId);
+  request->SetSuccess(aParam);
+
+  DispatchTrustedEventToRequest(SUCCESS_EVENT_NAME, request);
+
+  mRequests.ReplaceObjectAt(nsnull, aRequestId);
+}
+
+void
+SmsRequestManager::NotifyError(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+{
+  SmsRequest* request = GetRequest(aRequestId);
+  request->SetError(aError);
+
+  DispatchTrustedEventToRequest(ERROR_EVENT_NAME, request);
+
+  mRequests.ReplaceObjectAt(nsnull, aRequestId);
+}
+
+void
+SmsRequestManager::NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+  NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
+}
+
+void
+SmsRequestManager::NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+{
+  NotifyError(aRequestId, aError);
+}
+
+void
+SmsRequestManager::NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+  NotifySuccess<nsIDOMMozSmsMessage*>(aRequestId, aMessage);
+}
+
+void
+SmsRequestManager::NotifyGetSmsFailed(PRInt32 aRequestId,
+                                      SmsRequest::ErrorType aError)
+{
+  NotifyError(aRequestId, aError);
+}
+
+void
+SmsRequestManager::NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted)
+{
+  NotifySuccess<bool>(aRequestId, aDeleted);
+}
+
+void
+SmsRequestManager::NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError)
+{
+  NotifyError(aRequestId, aError);
+}
+
+void
+SmsRequestManager::NotifyNoMessageInList(PRInt32 aRequestId)
+{
+  SmsRequest* request = GetRequest(aRequestId);
+
+  nsCOMPtr<nsIDOMMozSmsCursor> cursor = request->GetCursor();
+  if (!cursor) {
+    cursor = new SmsCursor();
+  } else {
+    static_cast<SmsCursor*>(cursor.get())->Disconnect();
+  }
+
+  NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+}
+
+void
+SmsRequestManager::NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId,
+                                           nsIDOMMozSmsMessage* aMessage)
+{
+  SmsRequest* request = GetRequest(aRequestId);
+
+  nsCOMPtr<SmsCursor> cursor = new SmsCursor(aListId, request);
+  cursor->SetMessage(aMessage);
+
+  NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+}
+
+void
+SmsRequestManager::NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage)
+{
+  SmsRequest* request = GetRequest(aRequestId);
+
+  nsCOMPtr<SmsCursor> cursor = static_cast<SmsCursor*>(request->GetCursor());
+  NS_ASSERTION(cursor, "Request should have an cursor in that case!");
+  cursor->SetMessage(aMessage);
+
+  NotifySuccess<nsIDOMMozSmsCursor*>(aRequestId, cursor);
+}
+
+void
+SmsRequestManager::NotifyReadMessageListFailed(PRInt32 aRequestId,
+                                               SmsRequest::ErrorType aError)
+{
+  SmsRequest* request = GetRequest(aRequestId);
+
+  nsCOMPtr<nsIDOMMozSmsCursor> cursor = request->GetCursor();
+  if (cursor) {
+    static_cast<SmsCursor*>(cursor.get())->Disconnect();
+  }
+
+  NotifyError(aRequestId, aError);
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/SmsRequestManager.h
@@ -0,0 +1,96 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_sms_SmsRequestManager_h
+#define mozilla_dom_sms_SmsRequestManager_h
+
+#include "nsCOMArray.h"
+#include "SmsRequest.h"
+
+class nsIDOMMozSmsRequest;
+class nsPIDOMWindow;
+class nsIScriptContext;
+class nsIDOMMozSmsMessage;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsRequestManager
+{
+public:
+  static void Init();
+  static void Shutdown();
+  static SmsRequestManager* GetInstance();
+
+  PRInt32 CreateRequest(nsPIDOMWindow* aWindow,
+                        nsIScriptContext* aScriptContext,
+                        nsIDOMMozSmsRequest** aRequest);
+
+  PRInt32 AddRequest(nsIDOMMozSmsRequest* aRequest);
+
+  void NotifySmsSent(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
+  void NotifySmsSendFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+  void NotifyGotSms(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
+  void NotifyGetSmsFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+  void NotifySmsDeleted(PRInt32 aRequestId, bool aDeleted);
+  void NotifySmsDeleteFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+  void NotifyNoMessageInList(PRInt32 aRequestId);
+  void NotifyCreateMessageList(PRInt32 aRequestId, PRInt32 aListId, nsIDOMMozSmsMessage* aMessage);
+  void NotifyGotNextMessage(PRInt32 aRequestId, nsIDOMMozSmsMessage* aMessage);
+  void NotifyReadMessageListFailed(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+
+private:
+  static SmsRequestManager* sInstance;
+
+  nsresult DispatchTrustedEventToRequest(const nsAString& aEventName,
+                                         nsIDOMMozSmsRequest* aRequest);
+  SmsRequest* GetRequest(PRInt32 aRequestId);
+
+  template <class T>
+  void NotifySuccess(PRInt32 aRequestId, T aParam);
+  void NotifyError(PRInt32 aRequestId, SmsRequest::ErrorType aError);
+
+  nsCOMArray<nsIDOMMozSmsRequest> mRequests;
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsRequestManager_h
rename from dom/sms/src/SmsServiceFactory.cpp
rename to dom/sms/src/SmsServicesFactory.cpp
--- a/dom/sms/src/SmsServiceFactory.cpp
+++ b/dom/sms/src/SmsServicesFactory.cpp
@@ -30,34 +30,49 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "SmsServiceFactory.h"
+#include "SmsServicesFactory.h"
 #include "nsXULAppAPI.h"
 #include "SmsService.h"
+#include "SmsDatabaseService.h"
 #include "SmsIPCService.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 /* static */ already_AddRefed<nsISmsService>
-SmsServiceFactory::Create()
+SmsServicesFactory::CreateSmsService()
 {
   nsCOMPtr<nsISmsService> smsService;
 
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     smsService = new SmsIPCService();
   } else {
     smsService = new SmsService();
   }
 
   return smsService.forget();
 }
 
+/* static */ already_AddRefed<nsISmsDatabaseService>
+SmsServicesFactory::CreateSmsDatabaseService()
+{
+  nsCOMPtr<nsISmsDatabaseService> smsDBService;
+
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    smsDBService = new SmsIPCService();
+  } else {
+    smsDBService = new SmsDatabaseService();
+  }
+
+  return smsDBService.forget();
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
rename from dom/sms/src/SmsServiceFactory.h
rename to dom/sms/src/SmsServicesFactory.h
--- a/dom/sms/src/SmsServiceFactory.h
+++ b/dom/sms/src/SmsServicesFactory.h
@@ -30,30 +30,32 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef mozilla_dom_sms_SmsServiceFactory_h
-#define mozilla_dom_sms_SmsServiceFactory_h
+#ifndef mozilla_dom_sms_SmsServicesFactory_h
+#define mozilla_dom_sms_SmsServicesFactory_h
 
 #include "nsCOMPtr.h"
 
 class nsISmsService;
+class nsISmsDatabaseService;
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
-class SmsServiceFactory
+class SmsServicesFactory
 {
 public:
-  static already_AddRefed<nsISmsService> Create();
+  static already_AddRefed<nsISmsService> CreateSmsService();
+  static already_AddRefed<nsISmsDatabaseService> CreateSmsDatabaseService();
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_sms_SmsServiceFactory_h
+#endif // mozilla_dom_sms_SmsServicesFactory_h
--- a/dom/sms/src/Types.h
+++ b/dom/sms/src/Types.h
@@ -33,39 +33,44 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_sms_Types_h
 #define mozilla_dom_sms_Types_h
 
+#include "IPCMessageUtils.h"
+
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 // For SmsMessageDate.delivery.
+// Please keep the following files in sync with enum below:
+// embedding/android/GeckoSmsManager.java
 enum DeliveryState {
-  eDeliveryState_Sent,
+  eDeliveryState_Sent = 0,
   eDeliveryState_Received,
+  eDeliveryState_Unknown,
   // This state should stay at the end.
-  eDeliveryState_Unknown
+  eDeliveryState_EndGuard
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 namespace IPC {
 
 /**
  * Delivery state serializer.
  */
 template <>
 struct ParamTraits<mozilla::dom::sms::DeliveryState>
   : public EnumSerializer<mozilla::dom::sms::DeliveryState,
                           mozilla::dom::sms::eDeliveryState_Sent,
-                          mozilla::dom::sms::eDeliveryState_Unknown>
+                          mozilla::dom::sms::eDeliveryState_EndGuard>
 {};
 
 } // namespace IPC
 
 #endif // mozilla_dom_sms_Types_h
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/android/SmsDatabaseService.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SmsFilter.h"
+#include "SmsDatabaseService.h"
+#include "AndroidBridge.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_ISUPPORTS1(SmsDatabaseService, nsISmsDatabaseService)
+
+NS_IMETHODIMP
+SmsDatabaseService::SaveSentMessage(const nsAString& aReceiver,
+                                    const nsAString& aBody,
+                                    PRUint64 aDate, PRInt32* aId)
+{
+  *aId = -1;
+
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  *aId = AndroidBridge::Bridge()->SaveSentMessage(aReceiver, aBody, aDate);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
+                                  PRUint64 aProcessId)
+{
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  AndroidBridge::Bridge()->GetMessage(aMessageId, aRequestId, aProcessId);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
+                                  PRUint64 aProcessId)
+{
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  AndroidBridge::Bridge()->DeleteMessage(aMessageId, aRequestId, aProcessId);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::CreateMessageList(nsIDOMMozSmsFilter* aFilter,
+                                      bool aReverse, PRInt32 aRequestId,
+                                      PRUint64 aProcessId)
+{
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  AndroidBridge::Bridge()->CreateMessageList(
+    static_cast<SmsFilter*>(aFilter)->GetData(), aReverse, aRequestId, aProcessId
+  );
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
+                                         PRUint64 aProcessId)
+{
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  AndroidBridge::Bridge()->GetNextMessageInList(aListId, aRequestId, aProcessId);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::ClearMessageList(PRInt32 aListId)
+{
+  if (!AndroidBridge::Bridge()) {
+    return NS_OK;
+  }
+
+  AndroidBridge::Bridge()->ClearMessageList(aListId);
+  return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/android/SmsDatabaseService.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_sms_SmsDatabaseService_h
+#define mozilla_dom_sms_SmsDatabaseService_h
+
+#include "nsISmsDatabaseService.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsDatabaseService : public nsISmsDatabaseService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISMSDATABASESERVICE
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsDatabaseService_h
--- a/dom/sms/src/android/SmsService.cpp
+++ b/dom/sms/src/android/SmsService.cpp
@@ -62,23 +62,25 @@ SmsService::GetNumberOfMessagesForText(c
     return NS_OK;
   }
 
   *aResult = AndroidBridge::Bridge()->GetNumberOfMessagesForText(aText);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsService::Send(const nsAString& aNumber, const nsAString& aMessage,
+                 PRInt32 aRequestId, PRUint64 aProcessId)
 {
   if (!AndroidBridge::Bridge()) {
     return NS_OK;
   }
 
-  AndroidBridge::Bridge()->SendMessage(aNumber, aMessage);
+  AndroidBridge::Bridge()->SendMessage(aNumber, aMessage, aRequestId,
+                                       aProcessId);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsService::CreateSmsMessage(PRInt32 aId,
                              const nsAString& aDelivery,
                              const nsAString& aSender,
                              const nsAString& aReceiver,
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/fallback/SmsDatabaseService.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SmsDatabaseService.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_ISUPPORTS1(SmsDatabaseService, nsISmsDatabaseService)
+
+NS_IMETHODIMP
+SmsDatabaseService::SaveSentMessage(const nsAString& aReceiver,
+                                    const nsAString& aBody,
+                                    PRUint64 aDate, PRInt32* aId)
+{
+  *aId = -1;
+  NS_ERROR("We should not be here!");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
+                                  PRUint64 aProcessId)
+{
+  NS_ERROR("We should not be here!");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
+                                  PRUint64 aProcessId)
+{
+  NS_ERROR("We should not be here!");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::CreateMessageList(nsIDOMMozSmsFilter* aFilter,
+                                      bool aReverse, PRInt32 aRequestId,
+                                      PRUint64 aProcessId)
+{
+  NS_ERROR("We should not be here!");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
+                                         PRUint64 aProcessId)
+{
+  NS_ERROR("We should not be here!");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsDatabaseService::ClearMessageList(PRInt32 aListId)
+{
+  NS_ERROR("We should not be here!");
+  return NS_OK;
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/fallback/SmsDatabaseService.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_sms_SmsDatabaseService_h
+#define mozilla_dom_sms_SmsDatabaseService_h
+
+#include "nsISmsDatabaseService.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsDatabaseService : public nsISmsDatabaseService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISMSDATABASESERVICE
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsDatabaseService_h
--- a/dom/sms/src/fallback/SmsService.cpp
+++ b/dom/sms/src/fallback/SmsService.cpp
@@ -57,17 +57,18 @@ NS_IMETHODIMP
 SmsService::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
 {
   NS_ERROR("We should not be here!");
   *aResult = 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsService::Send(const nsAString& aNumber, const nsAString& aMessage,
+                 PRInt32 aRequestId, PRUint64 aProcessId)
 {
   NS_ERROR("We should not be here!");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsService::CreateSmsMessage(PRInt32 aId,
                              const nsAString& aDelivery,
--- a/dom/sms/src/ipc/PSms.ipdl
+++ b/dom/sms/src/ipc/PSms.ipdl
@@ -50,29 +50,81 @@ struct SmsMessageData {
   PRInt32       id;
   DeliveryState delivery;
   nsString      sender;
   nsString      receiver;
   nsString      body;
   PRUint64      timestamp; // ms since epoch.
 };
 
+struct SmsFilterData {
+  PRUint64      startDate;
+  PRUint64      endDate;
+  nsString[]    numbers;
+  DeliveryState delivery;
+};
+
 sync protocol PSms {
     manager PContent;
 
 child:
     NotifyReceivedMessage(SmsMessageData aMessageData);
 
+    NotifySentMessage(SmsMessageData aMessageData);
+
+    NotifyDeliveredMessage(SmsMessageData aMessageData);
+
+    NotifyRequestSmsSent(SmsMessageData aMessageData, PRInt32 aRequestId,
+                         PRUint64 aProcessId);
+
+    NotifyRequestSmsSendFailed(PRInt32 aError, PRInt32 aRequestId,
+                               PRUint64 aProcessId);
+
+    NotifyRequestGotSms(SmsMessageData aMessageData, PRInt32 aRequestId,
+                        PRUint64 aProcessId);
+
+    NotifyRequestGetSmsFailed(PRInt32 aError, PRInt32 aRequestId,
+                              PRUint64 aProcessId);
+
+    NotifyRequestSmsDeleted(bool aDeleted, PRInt32 aRequestId,
+                            PRUint64 aProcessId);
+
+    NotifyRequestSmsDeleteFailed(PRInt32 aError, PRInt32 aRequestId,
+                                 PRUint64 aProcessId);
+
+    NotifyRequestNoMessageInList(PRInt32 aRequestId, PRUint64 aProcessId);
+
+    NotifyRequestCreateMessageList(PRInt32 aListId, SmsMessageData aMessageData, PRInt32 aRequestId, PRUint64 aProcessId);
+
+    NotifyRequestGotNextMessage(SmsMessageData aMessageData, PRInt32 aRequestId, PRUint64 aProcessId);
+
+    NotifyRequestReadListFailed(PRInt32 aError, PRInt32 aRequestId,
+                                PRUint64 aProcessId);
+
 parent:
     sync HasSupport()
         returns (bool aHasSupport);
 
     sync GetNumberOfMessagesForText(nsString aText)
         returns (PRUint16 aNumber);
 
-    SendMessage(nsString aNumber, nsString aMessage);
+    SendMessage(nsString aNumber, nsString aMessage, PRInt32 aRequestId,
+                PRUint64 aProcessId);
+
+    sync SaveSentMessage(nsString aReceiver, nsString aBody, PRUint64 aDate)
+        returns (PRInt32 aId);
+
+    GetMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
+
+    DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
+
+    CreateMessageList(SmsFilterData aFilter, bool aReverse, PRInt32 aRequestId, PRUint64 aProcessId);
+
+    GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint64 aProcessId);
+
+    ClearMessageList(PRInt32 aListId);
 
     __delete__();
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/SmsChild.cpp
+++ b/dom/sms/src/ipc/SmsChild.cpp
@@ -35,16 +35,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "SmsChild.h"
 #include "SmsMessage.h"
 #include "Constants.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
+#include "mozilla/dom/ContentChild.h"
+#include "SmsRequestManager.h"
+#include "SmsRequest.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 bool
 SmsChild::RecvNotifyReceivedMessage(const SmsMessageData& aMessageData)
 {
@@ -54,11 +57,183 @@ SmsChild::RecvNotifyReceivedMessage(cons
   }
 
   nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
   obs->NotifyObservers(message, kSmsReceivedObserverTopic, nsnull);
 
   return true;
 }
 
+bool
+SmsChild::RecvNotifySentMessage(const SmsMessageData& aMessageData)
+{
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (!obs) {
+    return true;
+  }
+
+  nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
+  obs->NotifyObservers(message, kSmsSentObserverTopic, nsnull);
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyDeliveredMessage(const SmsMessageData& aMessageData)
+{
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (!obs) {
+    return true;
+  }
+
+  nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
+  obs->NotifyObservers(message, kSmsDeliveredObserverTopic, nsnull);
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsSent(const SmsMessageData& aMessage,
+                                   const PRInt32& aRequestId,
+                                   const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessage);
+  SmsRequestManager::GetInstance()->NotifySmsSent(aRequestId, message);
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsSendFailed(const PRInt32& aError,
+                                         const PRInt32& aRequestId,
+                                         const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  SmsRequestManager::GetInstance()->NotifySmsSendFailed(aRequestId,
+                                                        SmsRequest::ErrorType(aError));
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestGotSms(const SmsMessageData& aMessage,
+                                  const PRInt32& aRequestId,
+                                  const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessage);
+  SmsRequestManager::GetInstance()->NotifyGotSms(aRequestId, message);
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestGetSmsFailed(const PRInt32& aError,
+                                        const PRInt32& aRequestId,
+                                        const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  SmsRequestManager::GetInstance()->NotifyGetSmsFailed(aRequestId,
+                                                       SmsRequest::ErrorType(aError));
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsDeleted(const bool& aDeleted,
+                                      const PRInt32& aRequestId,
+                                      const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  SmsRequestManager::GetInstance()->NotifySmsDeleted(aRequestId, aDeleted);
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestSmsDeleteFailed(const PRInt32& aError,
+                                           const PRInt32& aRequestId,
+                                           const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  SmsRequestManager::GetInstance()->NotifySmsDeleteFailed(aRequestId,
+                                                          SmsRequest::ErrorType(aError));
+
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestNoMessageInList(const PRInt32& aRequestId,
+                                           const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  SmsRequestManager::GetInstance()->NotifyNoMessageInList(aRequestId);
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestCreateMessageList(const PRInt32& aListId,
+                                             const SmsMessageData& aMessageData,
+                                             const PRInt32& aRequestId,
+                                             const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
+  SmsRequestManager::GetInstance()->NotifyCreateMessageList(aRequestId, aListId, message);
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessageData,
+                                          const PRInt32& aRequestId,
+                                          const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(aMessageData);
+  SmsRequestManager::GetInstance()->NotifyGotNextMessage(aRequestId, message);
+  return true;
+}
+
+bool
+SmsChild::RecvNotifyRequestReadListFailed(const PRInt32& aError,
+                                          const PRInt32& aRequestId,
+                                          const PRUint64& aProcessId)
+{
+  if (ContentChild::GetSingleton()->GetID() != aProcessId) {
+    return true;
+  }
+
+  SmsRequestManager::GetInstance()->NotifyReadMessageListFailed(aRequestId,
+                                                                SmsRequest::ErrorType(aError));
+  return true;
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/SmsChild.h
+++ b/dom/sms/src/ipc/SmsChild.h
@@ -43,15 +43,27 @@
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 class SmsChild : public PSmsChild
 {
 public:
   NS_OVERRIDE virtual bool RecvNotifyReceivedMessage(const SmsMessageData& aMessage);
+  NS_OVERRIDE virtual bool RecvNotifySentMessage(const SmsMessageData& aMessage);
+  NS_OVERRIDE virtual bool RecvNotifyDeliveredMessage(const SmsMessageData& aMessage);
+  NS_OVERRIDE virtual bool RecvNotifyRequestSmsSent(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestSmsSendFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestGotSms(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestGetSmsFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestSmsDeleted(const bool& aDeleted, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestSmsDeleteFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestNoMessageInList(const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestCreateMessageList(const PRInt32& aListId, const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestGotNextMessage(const SmsMessageData& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvNotifyRequestReadListFailed(const PRInt32& aError, const PRInt32& aRequestId, const PRUint64& aProcessId);
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_sms_SmsChild_h
--- a/dom/sms/src/ipc/SmsIPCService.cpp
+++ b/dom/sms/src/ipc/SmsIPCService.cpp
@@ -36,35 +36,39 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/dom/ContentChild.h"
 #include "SmsIPCService.h"
 #include "nsXULAppAPI.h"
 #include "jsapi.h"
 #include "mozilla/dom/sms/SmsChild.h"
 #include "mozilla/dom/sms/SmsMessage.h"
+#include "SmsFilter.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 PSmsChild* SmsIPCService::sSmsChild = nsnull;
 
-NS_IMPL_ISUPPORTS1(SmsIPCService, nsISmsService)
+NS_IMPL_ISUPPORTS2(SmsIPCService, nsISmsService, nsISmsDatabaseService)
 
 /* static */ PSmsChild*
 SmsIPCService::GetSmsChild()
 {
   if (!sSmsChild) {
     sSmsChild = ContentChild::GetSingleton()->SendPSmsConstructor();
   }
 
   return sSmsChild;
 }
 
+/*
+ * Implementation of nsISmsService.
+ */
 NS_IMETHODIMP
 SmsIPCService::HasSupport(bool* aHasSupport)
 {
   GetSmsChild()->SendHasSupport(aHasSupport);
 
   return NS_OK;
 }
 
@@ -72,19 +76,21 @@ NS_IMETHODIMP
 SmsIPCService::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
 {
   GetSmsChild()->SendGetNumberOfMessagesForText(nsString(aText), aResult);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsIPCService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsIPCService::Send(const nsAString& aNumber, const nsAString& aMessage,
+                    PRInt32 aRequestId, PRUint64 aProcessId)
 {
-  GetSmsChild()->SendSendMessage(nsString(aNumber), nsString(aMessage));
+  GetSmsChild()->SendSendMessage(nsString(aNumber), nsString(aMessage),
+                                 aRequestId, ContentChild::GetSingleton()->GetID());
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsIPCService::CreateSmsMessage(PRInt32 aId,
                                 const nsAString& aDelivery,
                                 const nsAString& aSender,
@@ -93,11 +99,70 @@ SmsIPCService::CreateSmsMessage(PRInt32 
                                 const jsval& aTimestamp,
                                 JSContext* aCx,
                                 nsIDOMMozSmsMessage** aMessage)
 {
   return SmsMessage::Create(
     aId, aDelivery, aSender, aReceiver, aBody, aTimestamp, aCx, aMessage);
 }
 
+/*
+ * Implementation of nsISmsDatabaseService.
+ */
+NS_IMETHODIMP
+SmsIPCService::SaveSentMessage(const nsAString& aReceiver,
+                               const nsAString& aBody,
+                               PRUint64 aDate, PRInt32* aId)
+{
+  GetSmsChild()->SendSaveSentMessage(nsString(aReceiver), nsString(aBody),
+                                     aDate, aId);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
+                             PRUint64 aProcessId)
+{
+  GetSmsChild()->SendGetMessage(aMessageId, aRequestId,
+                                ContentChild::GetSingleton()->GetID());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
+                             PRUint64 aProcessId)
+{
+  GetSmsChild()->SendDeleteMessage(aMessageId, aRequestId,
+                                   ContentChild::GetSingleton()->GetID());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::CreateMessageList(nsIDOMMozSmsFilter* aFilter, bool aReverse,
+                                 PRInt32 aRequestId, PRUint64 aProcessId)
+{
+  SmsFilter* filter = static_cast<SmsFilter*>(aFilter);
+  GetSmsChild()->SendCreateMessageList(filter->GetData(), aReverse, aRequestId,
+                                       ContentChild::GetSingleton()->GetID());
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
+                                    PRUint64 aProcessId)
+{
+  GetSmsChild()->SendGetNextMessageInList(aListId, aRequestId,
+                                          ContentChild::GetSingleton()->GetID());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsIPCService::ClearMessageList(PRInt32 aListId)
+{
+  GetSmsChild()->SendClearMessageList(aListId);
+  return NS_OK;
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/SmsIPCService.h
+++ b/dom/sms/src/ipc/SmsIPCService.h
@@ -34,28 +34,31 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_sms_SmsIPCService_h
 #define mozilla_dom_sms_SmsIPCService_h
 
 #include "nsISmsService.h"
+#include "nsISmsDatabaseService.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 class PSmsChild;
 
 class SmsIPCService : public nsISmsService
+                    , public nsISmsDatabaseService
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISMSSERVICE
+  NS_DECL_NSISMSDATABASESERVICE
 
 private:
   static PSmsChild* GetSmsChild();
   static PSmsChild* sSmsChild;
 };
 
 } // namespace sms
 } // namespace dom
--- a/dom/sms/src/ipc/SmsParent.cpp
+++ b/dom/sms/src/ipc/SmsParent.cpp
@@ -38,42 +38,74 @@
 #include "SmsParent.h"
 #include "nsISmsService.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "Constants.h"
 #include "nsIDOMSmsMessage.h"
 #include "mozilla/unused.h"
 #include "SmsMessage.h"
+#include "nsISmsDatabaseService.h"
+#include "SmsFilter.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
+nsTArray<SmsParent*>* SmsParent::gSmsParents = nsnull;
+
 NS_IMPL_ISUPPORTS1(SmsParent, nsIObserver)
 
+/* static */ void
+SmsParent::GetAll(nsTArray<SmsParent*>& aArray)
+{
+  if (!gSmsParents) {
+    aArray.Clear();
+    return;
+  }
+
+  aArray = *gSmsParents;
+}
+
 SmsParent::SmsParent()
 {
+  if (!gSmsParents) {
+    gSmsParents = new nsTArray<SmsParent*>();
+  }
+
+  gSmsParents->AppendElement(this);
+
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return;
   }
 
   obs->AddObserver(this, kSmsReceivedObserverTopic, false);
+  obs->AddObserver(this, kSmsSentObserverTopic, false);
+  obs->AddObserver(this, kSmsDeliveredObserverTopic, false);
 }
 
 void
 SmsParent::ActorDestroy(ActorDestroyReason why)
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return;
   }
 
   obs->RemoveObserver(this, kSmsReceivedObserverTopic);
+  obs->RemoveObserver(this, kSmsSentObserverTopic);
+  obs->RemoveObserver(this, kSmsDeliveredObserverTopic);
+
+  NS_ASSERTION(gSmsParents, "gSmsParents can't be null at that point!");
+  gSmsParents->RemoveElement(this);
+  if (gSmsParents->Length() == 0) {
+    delete gSmsParents;
+    gSmsParents = nsnull;
+  }
 }
 
 NS_IMETHODIMP
 SmsParent::Observe(nsISupports* aSubject, const char* aTopic,
                    const PRUnichar* aData)
 {
   if (!strcmp(aTopic, kSmsReceivedObserverTopic)) {
     nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
@@ -81,48 +113,152 @@ SmsParent::Observe(nsISupports* aSubject
       NS_ERROR("Got a 'sms-received' topic without a valid message!");
       return NS_OK;
     }
 
     unused << SendNotifyReceivedMessage(static_cast<SmsMessage*>(message.get())->GetData());
     return NS_OK;
   }
 
+  if (!strcmp(aTopic, kSmsSentObserverTopic)) {
+    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+    if (!message) {
+      NS_ERROR("Got a 'sms-sent' topic without a valid message!");
+      return NS_OK;
+    }
+
+    unused << SendNotifySentMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    return NS_OK;
+  }
+
+  if (!strcmp(aTopic, kSmsDeliveredObserverTopic)) {
+    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
+    if (!message) {
+      NS_ERROR("Got a 'sms-delivered' topic without a valid message!");
+      return NS_OK;
+    }
+
+    unused << SendNotifyDeliveredMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    return NS_OK;
+  }
+
   return NS_OK;
 }
 
 bool
 SmsParent::RecvHasSupport(bool* aHasSupport)
 {
   *aHasSupport = false;
 
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, true);
 
   smsService->HasSupport(aHasSupport);
   return true;
 }
 
 bool
 SmsParent::RecvGetNumberOfMessagesForText(const nsString& aText, PRUint16* aResult)
 {
   *aResult = 0;
 
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, true);
 
   smsService->GetNumberOfMessagesForText(aText, aResult);
   return true;
 }
 
 bool
-SmsParent::RecvSendMessage(const nsString& aNumber, const nsString& aMessage)
+SmsParent::RecvSendMessage(const nsString& aNumber, const nsString& aMessage,
+                           const PRInt32& aRequestId, const PRUint64& aProcessId)
 {
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMSSERVICE_CONTRACTID);
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, true);
 
-  smsService->Send(aNumber, aMessage);
+  smsService->Send(aNumber, aMessage, aRequestId, aProcessId);
+  return true;
+}
+
+bool
+SmsParent::RecvSaveSentMessage(const nsString& aRecipient,
+                               const nsString& aBody,
+                               const PRUint64& aDate, PRInt32* aId)
+{
+  *aId = -1;
+
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, true);
+
+  smsDBService->SaveSentMessage(aRecipient, aBody, aDate, aId);
+  return true;
+}
+
+bool
+SmsParent::RecvGetMessage(const PRInt32& aMessageId, const PRInt32& aRequestId,
+                          const PRUint64& aProcessId)
+{
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, true);
+
+  smsDBService->GetMessageMoz(aMessageId, aRequestId, aProcessId);
+  return true;
+}
+
+bool
+SmsParent::RecvDeleteMessage(const PRInt32& aMessageId, const PRInt32& aRequestId,
+                             const PRUint64& aProcessId)
+{
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, true);
+
+  smsDBService->DeleteMessage(aMessageId, aRequestId, aProcessId);
+  return true;
+}
+
+bool
+SmsParent::RecvCreateMessageList(const SmsFilterData& aFilter,
+                                 const bool& aReverse,
+                                 const PRInt32& aRequestId,
+                                 const PRUint64& aProcessId)
+{
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, true);
+
+  nsCOMPtr<nsIDOMMozSmsFilter> filter = new SmsFilter(aFilter);
+  smsDBService->CreateMessageList(filter, aReverse, aRequestId, aProcessId);
+
+  return true;
+}
+
+bool
+SmsParent::RecvGetNextMessageInList(const PRInt32& aListId,
+                                    const PRInt32& aRequestId,
+                                    const PRUint64& aProcessId)
+{
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, true);
+
+  smsDBService->GetNextMessageInList(aListId, aRequestId, aProcessId);
+
+  return true;
+}
+
+bool
+SmsParent::RecvClearMessageList(const PRInt32& aListId)
+{
+  nsCOMPtr<nsISmsDatabaseService> smsDBService =
+    do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(smsDBService, true);
+
+  smsDBService->ClearMessageList(aListId);
+
   return true;
 }
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/SmsParent.h
+++ b/dom/sms/src/ipc/SmsParent.h
@@ -47,23 +47,34 @@ namespace sms {
 
 class SmsParent : public PSmsParent
                 , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
+  static void GetAll(nsTArray<SmsParent*>& aArray);
+
   SmsParent();
 
   NS_OVERRIDE virtual bool RecvHasSupport(bool* aHasSupport);
   NS_OVERRIDE virtual bool RecvGetNumberOfMessagesForText(const nsString& aText, PRUint16* aResult);
-  NS_OVERRIDE virtual bool RecvSendMessage(const nsString& aNumber, const nsString& aMessage);
+  NS_OVERRIDE virtual bool RecvSendMessage(const nsString& aNumber, const nsString& aMessage, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvSaveSentMessage(const nsString& aRecipient, const nsString& aBody, const PRUint64& aDate, PRInt32* aId);
+  NS_OVERRIDE virtual bool RecvGetMessage(const PRInt32& aMessageId, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvDeleteMessage(const PRInt32& aMessageId, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvCreateMessageList(const SmsFilterData& aFilter, const bool& aReverse, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvGetNextMessageInList(const PRInt32& aListId, const PRInt32& aRequestId, const PRUint64& aProcessId);
+  NS_OVERRIDE virtual bool RecvClearMessageList(const PRInt32& aListId);
 
 protected:
   virtual void ActorDestroy(ActorDestroyReason why);
+
+private:
+  static nsTArray<SmsParent*>* gSmsParents;
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_sms_SmsParent_h
--- a/dom/sms/tests/Makefile.in
+++ b/dom/sms/tests/Makefile.in
@@ -45,16 +45,17 @@ include $(DEPTH)/config/autoconf.mk
 
 DIRS = \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
   test_sms_basics.html \
+  test_smsfilter.html \
   $(NULL)
 
 _CHROME_TEST_FILES = \
   $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
--- a/dom/sms/tests/test_sms_basics.html
+++ b/dom/sms/tests/test_sms_basics.html
@@ -40,16 +40,19 @@ function checkInterface(aInterface) {
 function test() {
   var gSmsEnabled = SpecialPowers.getBoolPref("dom.sms.enabled");
   var gSmsWhiteList = SpecialPowers.getCharPref("dom.sms.whitelist");
 
   checkInterface("SmsManager");
   checkInterface("NavigatorSms");
   checkInterface("SmsMessage");
   checkInterface("SmsEvent");
+  checkInterface("SmsRequest");
+  checkInterface("SmsFilter");
+  checkInterface("SmsCursor");
 
   // If sms are disabled and whitelist is empty, sms is disabled.
   SpecialPowers.setBoolPref("dom.sms.enabled", false);
   SpecialPowers.setCharPref("dom.sms.whitelist", "");
   checkSmsDisabled();
 
   // If sms are enabled and whitelist is empty, sms are disabled.
   SpecialPowers.setBoolPref("dom.sms.enabled", true);
new file mode 100644
--- /dev/null
+++ b/dom/sms/tests/test_smsfilter.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test SmsFilter</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test SmsFilter **/
+
+function throwingCheck(aFilter, aProperty, disallowedValue)
+{
+  disallowedValue.forEach(function(v) {
+    var exception = false;
+    try {
+      aFilter[aProperty] = v;
+    } catch (e) {
+      exception = true;
+    }
+    ok(exception, "An exception should have been thrown");
+  });
+}
+
+var filter = new MozSmsFilter();
+
+isnot(filter, null, "filter should be set");
+
+is(filter.startDate, null, "Parameters shouldn't be initialized");
+is(filter.endDate, null, "Parameters shouldn't be initialized");
+is(filter.numbers, null, "Parameters shouldn't be initialized");
+is(filter.delivery, null, "Parameters shouldn't be initialized");
+
+var date = new Date();
+filter.startDate = date;
+is(filter.startDate, "" + date, "Setters and getters should work!");
+filter.startDate = null;
+is(filter.startDate, null, "null should revert the value to default");
+throwingCheck(filter, 'startDate', [ "foo", 42, [1, 2], function () {}, undefined ]);
+
+filter.endDate = date;
+is(filter.endDate, "" + date, "Setters and getters should work!");
+filter.endDate = null;
+is(filter.endDate, null, "null should revert the value to default");
+throwingCheck(filter, 'endDate', [ "foo", 42, [1, 2], function () {}, undefined ]);
+
+var numbers = [ "foo", "bar" ];
+filter.numbers = numbers;
+is(filter.numbers, "" + numbers, "Setters and getters should work!");
+filter.numbers = null;
+is(filter.numbers, null, "null should revert the value to default");
+throwingCheck(filter, 'numbers', [ "foo", 42, function () {}, new Date(), undefined ]);
+
+filter.delivery = "sent";
+is(filter.delivery, "sent", "Setters and getters should work!");
+filter.delivery = "received";
+is(filter.delivery, "received", "Setters and getters should work!");
+filter.delivery = "";
+is(filter.delivery, null, "The empty string should revert the value to default.");
+filter.delivery = null;
+is(filter.delivery, null, "'null' should revert the value to default.");
+throwingCheck(filter, 'delivery', [ "foo", 42, [1, 2], function () {}, new Date(), undefined ]);
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/telephony/nsITelephone.idl
+++ b/dom/telephony/nsITelephone.idl
@@ -48,32 +48,63 @@ interface nsITelephoneCallback : nsISupp
   // 'callState' uses the CALL_STATE values from nsITelephone. Return true to
   // continue enumeration or false to cancel.
   boolean enumerateCallState(in unsigned long callIndex,
                              in unsigned short callState,
                              in AString number,
                              in boolean isActive);
 };
 
-[scriptable, uuid(5be6e41d-3aee-4f5c-8284-95cf529dd6fe)]
+[scriptable, uuid(8399fddd-471c-41ac-8f35-99f7dbb738ec)]
+interface nsIDataCallInfo : nsISupports
+{
+  readonly attribute unsigned long callState;
+  readonly attribute AString cid;
+  readonly attribute AString apn;
+};
+
+[scriptable, uuid(36cc4b89-0338-4ff7-a3c2-d78e60f2ea98)]
+interface nsIPhoneDataCallCallback : nsISupports
+{
+  /**
+   * This method is called when the state of a data call is changed.
+   *
+   * @param dataState use DATACALL_STATE_* values from nsITelephone.
+   */
+  void dataCallStateChanged(in AString cid,
+                            in AString interfaceName,
+                            in unsigned short callState);
+
+  void receiveDataCallList([array,size_is(aLength)] in nsIDataCallInfo aDataCalls,
+                           in unsigned long aLength);
+};
+
+[scriptable, uuid(78ed0beb-d6ad-42f8-929a-8d003285784f)]
 interface nsITelephone : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_RINGING = 2;
   const unsigned short CALL_STATE_BUSY = 3;
   const unsigned short CALL_STATE_CONNECTING = 4;
   const unsigned short CALL_STATE_CONNECTED = 5;
   const unsigned short CALL_STATE_HOLDING = 6;
   const unsigned short CALL_STATE_HELD = 7;
   const unsigned short CALL_STATE_RESUMING = 8;
   const unsigned short CALL_STATE_DISCONNECTING = 9;
   const unsigned short CALL_STATE_DISCONNECTED = 10;
   const unsigned short CALL_STATE_INCOMING = 11;
 
+  // Keep consistent with GECKO_DATACALL_STATE_* values in ril_consts.js
+  const unsigned short DATACALL_STATE_UNKNOWN = 0;
+  const unsigned short DATACALL_STATE_CONNECTING = 1;
+  const unsigned short DATACALL_STATE_CONNECTED = 2;
+  const unsigned short DATACALL_STATE_DISCONNECTING = 3;
+  const unsigned short DATACALL_STATE_DISCONNECTED = 4;
+
   readonly attribute jsval currentState;
 
   void registerCallback(in nsITelephoneCallback callback);
   void unregisterCallback(in nsITelephoneCallback callback);
 
   /**
    * Will continue calling callback.enumerateCallState until the callback
    * returns false.
@@ -90,14 +121,28 @@ interface nsITelephone : nsISupports
   void stopTone();
 
   void answerCall(in unsigned long callIndex);
   void rejectCall(in unsigned long callIndex);
 
   attribute bool microphoneMuted;
   attribute bool speakerEnabled;
 
+  // PDP APIs
+  void setupDataCall(in long radioTech,
+                     in DOMString apn,
+                     in DOMString user,
+                     in DOMString passwd,
+                     in long chappap,
+                     in DOMString pdptype);
+  void deactivateDataCall(in DOMString cid,
+                          in DOMString reason);
+  void getDataCallList();
+  
+  void registerDataCallCallback(in nsIPhoneDataCallCallback callback);
+  void unregisterDataCallCallback(in nsIPhoneDataCallCallback callback);
+
   /**
    * SMS-related functionality.
    */
   unsigned short getNumberOfMessagesForText(in DOMString text);
   void sendSMS(in DOMString number, in DOMString message);
 };
--- a/dom/telephony/nsTelephonyWorker.js
+++ b/dom/telephony/nsTelephonyWorker.js
@@ -45,16 +45,18 @@ Cu.import("resource://gre/modules/Servic
 
 var RIL = {};
 Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
 const DEBUG = true; // set to false to suppress debug messages
 
 const TELEPHONYWORKER_CID =
   Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
+const DATACALLINFO_CID =
+  Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
 
 const nsIAudioManager = Ci.nsIAudioManager;
 const nsITelephone = Ci.nsITelephone;
 
 const kSmsReceivedObserverTopic          = "sms-received";
 const DOM_SMS_DELIVERY_RECEIVED          = "received";
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
@@ -105,16 +107,30 @@ XPCOMUtils.defineLazyGetter(this, "gAudi
   } catch (ex) {
     //TODO on the phone this should not fall back as silently.
     debug("Using fake audio manager.");
     return FakeAudioManager;
   }
 });
 
 
+function DataCallInfo(state, cid, apn) {
+  this.callState = state;
+  this.cid = cid;
+  this.apn = apn;
+}
+DataCallInfo.protoptype = {
+  classID:      DATACALLINFO_CID,
+  classInfo:    XPCOMUtils.generateCI({classID: DATACALLINFO_CID,
+                                       classDescription: "DataCallInfo",
+                                       interfaces: [Ci.nsIDataCallInfo]}),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInfo]),
+};
+
+
 function nsTelephonyWorker() {
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
   debug("Starting Worker\n");
   this.currentState = {
     signalStrength: null,
     operator:       null,
@@ -173,16 +189,22 @@ nsTelephonyWorker.prototype = {
         this.currentState.radioState = message.radioState;
         break;
       case "cardstatechange":
         this.currentState.cardState = message.cardState;
         break;
       case "sms-received":
         this.handleSmsReceived(message);
         return;
+      case "datacallstatechange":
+        this.handleDataCallState(message);
+        break;
+      case "datacalllist":
+        this.handleDataCallList(message);
+        break;
       default:
         throw new Error("Don't know about this message type: " + message.type);
     }
   },
 
   /**
    * Track the active call and update the audio system as its state changes.
    *
@@ -273,16 +295,39 @@ nsTelephonyWorker.prototype = {
                                            DOM_SMS_DELIVERY_RECEIVED,
                                            message.sender || null,
                                            message.receiver || null,
                                            message.body || null,
                                            message.timestamp);
     Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
   },
 
+  /**
+   * Handle data call state changes.
+   */
+  handleDataCallState: function handleDataCallState(message) {
+    let ifname = message.ifname ? message.ifname : "";
+    this._deliverDataCallCallback("dataCallStateChanged",
+                                  [message.cid, ifname, message.state]);
+  },
+
+  /**
+   * Handle data call list.
+   */
+  handleDataCallList: function handleDataCallList(message) {
+    let datacalls = [];
+    for each (let datacall in message.datacalls) {
+      datacalls.push(new DataCallInfo(datacall.state,
+                                      datacall.cid,
+                                      datacall.apn));
+    }
+    this._deliverDataCallCallback("receiveDataCallList",
+                                  [datacalls, datacalls.length]);
+  },
+
   // nsIRadioWorker
 
   worker: null,
 
   // nsITelephone
 
   currentState: null,
 
@@ -290,17 +335,17 @@ nsTelephonyWorker.prototype = {
     debug("Dialing " + number);
     this.worker.postMessage({type: "dial", number: number});
   },
 
   hangUp: function hangUp(callIndex) {
     debug("Hanging up call no. " + callIndex);
     this.worker.postMessage({type: "hangUp", callIndex: callIndex});
   },
-  
+
   startTone: function startTone(dtmfChar) {
     debug("Sending Tone for " + dtmfChar);
     this.worker.postMessage({type: "startTone", dtmfChar: dtmfChar});
   },
 
   stopTone: function stopTone() {
     debug("Stopping Tone");
     this.worker.postMessage({type: "stopTone"});
@@ -410,16 +455,94 @@ nsTelephonyWorker.prototype = {
       }
       try {
         handler.apply(callback, args);
       } catch (e) {
         debug("callback handler for " + name + " threw an exception: " + e);
       }
     }
   },
+
+  registerDataCallCallback: function registerDataCallCallback(callback) {
+    if (this._datacall_callbacks) {
+      if (this._datacall_callbacks.indexOf(callback) != -1) {
+        throw new Error("Already registered this callback!");
+      }
+    } else {
+      this._datacall_callbacks = [];
+    }
+    this._datacall_callbacks.push(callback);
+    debug("Registering callback: " + callback);
+  },
+
+  unregisterDataCallCallback: function unregisterDataCallCallback(callback) {
+    if (!this._datacall_callbacks) {
+      return;
+    }
+    let index = this._datacall_callbacks.indexOf(callback);
+    if (index != -1) {
+      this._datacall_callbacks.splice(index, 1);
+      debug("Unregistering callback: " + callback);
+    }
+  },
+
+  _deliverDataCallCallback: function _deliverDataCallCallback(name, args) {
+    // We need to worry about callback registration state mutations during the
+    // callback firing. The behaviour we want is to *not* call any callbacks
+    // that are added during the firing and to *not* call any callbacks that are
+    // removed during the firing. To address this, we make a copy of the
+    // callback list before dispatching and then double-check that each callback
+    // is still registered before calling it.
+    if (!this._datacall_callbacks) {
+      return;
+    }
+    let callbacks = this._datacall_callbacks.slice();
+    for each (let callback in callbacks) {
+      if (this._datacall_callbacks.indexOf(callback) == -1) {
+        continue;
+      }
+      let handler = callback[name];
+      if (typeof handler != "function") {
+        throw new Error("No handler for " + name);
+      }
+      try {
+        handler.apply(callback, args);
+      } catch (e) {
+        debug("callback handler for " + name + " threw an exception: " + e);
+      }
+    }
+  },
+
+  setupDataCall: function(radioTech, apn, user, passwd, chappap, pdptype) {
+    this.worker.postMessage({type: "setupDataCall",
+                             radioTech: radioTech,
+                             apn: apn,
+                             user: user,
+                             passwd: passwd,
+                             chappap: chappap,
+                             pdptype: pdptype});
+    this._deliverDataCallCallback("dataCallStateChanged",
+                                  [message.cid, "",
+                                   RIL.GECKO_DATACALL_STATE_CONNECTING]);
+  },
+
+  deactivateDataCall: function(cid, reason) {
+    this.worker.postMessage({type: "deactivateDataCall",
+                             cid: cid,
+                             reason: reason});
+    this._deliverDataCallCallback("dataCallStateChanged",
+                                  [message.cid,
+                                   "",
+                                   RIL.GECKO_DATACALL_STATE_DISCONNECTING]);
+  },
+
+  getDataCallList: function getDataCallList() {
+    this.worker.postMessage({type: "getDataCallList"});
+  },
+
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTelephonyWorker]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- TelephonyWorker component: " + s + "\n");
--- a/dom/telephony/ril_consts.js
+++ b/dom/telephony/ril_consts.js
@@ -402,11 +402,37 @@ const PDU_ALPHABET_7BIT_DEFAULT = [
   "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
   "\xe4",   // LATIN SMALL LETTER A WITH DIAERESIS
   "\xf6",   // LATIN SMALL LETTER O WITH DIAERESIS
   "\xf1",   // LATIN SMALL LETTER N WITH TILDE
   "\xfc",   // LATIN SMALL LETTER U WITH DIAERESIS
   "\xe0"    // LATIN SMALL LETTER A WITH GRAVE
 ];
 
+const DATACALL_RADIOTECHONLOGY_CDMA = 0;
+const DATACALL_RADIOTECHONLOGY_GSM = 1;
+
+const DATACALL_AUTH_NONE = 0;
+const DATACALL_AUTH_PAP = 1;
+const DATACALL_AUTH_CHAP = 2;
+const DATACALL_AUTH_PAP_OR_CHAP = 3;
+
+const DATACALL_PROFILE_DEFAULT = 0;
+const DATACALL_PROFILE_TETHERED = 1;
+const DATACALL_PROFILE_OEM_BASE = 1000;
+
+const DATACALL_DEACTIVATE_NO_REASON = 0;
+const DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1;
+
+const DATACALL_INACTIVE = 0;
+const DATACALL_ACTIVE_DOWN = 1;
+const DATACALL_ACTIVE_UP = 2;
+
+// Keep consistent with nsITelephone.DATACALL_STATE_*.
+const GECKO_DATACALL_STATE_UNKNOWN = 0;
+const GECKO_DATACALL_STATE_CONNECTING = 1;
+const GECKO_DATACALL_STATE_CONNECTED = 2;
+const GECKO_DATACALL_STATE_DISCONNECTING = 3;
+const GECKO_DATACALL_STATE_DISCONNECTED = 4;
+
 
 // Allow this file to be imported via Components.utils.import().
 const EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/telephony/ril_worker.js
+++ b/dom/telephony/ril_worker.js
@@ -111,16 +111,19 @@ let Buf = {
     this.currentParcelSize = 0;
 
     // This gets incremented each time we send out a parcel.
     this.token = 1;
 
     // Maps tokens we send out with requests to the request type, so that
     // when we get a response parcel back, we know what request it was for.
     this.tokenRequestMap = {};
+
+    // This is the token of last solicited response.
+    this.lastSolicitedToken = 0;
   },
 
   /**
    * Grow the incoming buffer.
    *
    * @param min_size
    *        Minimum new size. The actual new size will be the the smallest
    *        power of 2 that's larger than this number.
@@ -444,16 +447,17 @@ let Buf = {
         //TODO
         debug("Received error " + error + " for solicited parcel type " +
               request_type);
         return;
       }
       debug("Solicited response for request type " + request_type +
             ", token " + token);
       delete this.tokenRequestMap[token];
+      this.lastSolicitedToken = token;
     } else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
       request_type = this.readUint32();
       length -= UINT32_SIZE;
       debug("Unsolicited response for request type " + request_type);
     } else {
       debug("Unknown response type: " + response_type);
       return;
     }
@@ -745,17 +749,16 @@ let RIL = {
   },
 
   /**
    * Start a DTMF Tone.
    *
    * @param dtmfChar
    *        DTMF signal to send, 0-9, *, +
    */
-
   startTone: function startTone(dtmfChar) {
     Buf.newParcel(REQUEST_DTMF_START);
     Buf.writeString(dtmfChar);
     Buf.sendParcel();
   },
 
   stopTone: function stopTone() {
     Buf.simpleRequest(REQUEST_DTMF_STOP);
@@ -775,21 +778,88 @@ let RIL = {
   },
 
   /**
    * Set the Short Message Service Center address.
    *
    * @param smsc
    *        Short Message Service Center address in PDU format.
    */
-   setSMSCAddress: function setSMSCAddress(smsc) {
-     Buf.newParcel(REQUEST_SET_SMSC_ADDRESS);
-     Buf.writeString(smsc);
-     Buf.sendParcel();
-   },
+  setSMSCAddress: function setSMSCAddress(smsc) {
+    Buf.newParcel(REQUEST_SET_SMSC_ADDRESS);
+    Buf.writeString(smsc);
+    Buf.sendParcel();
+  },
+
+  /**
+   * Setup a data call.
+   *
+   * @param radioTech
+   *        Integer to indicate radio technology.
+   *        DATACALL_RADIOTECHONLOGY_CDMA => CDMA.
+   *        DATACALL_RADIOTECHONLOGY_GSM  => GSM.
+   * @param apn
+   *        String containing the name of the APN to connect to.
+   * @param user
+   *        String containing the username for the APN.
+   * @param passwd
+   *        String containing the password for the APN.
+   * @param chappap
+   *        Integer containing CHAP/PAP auth type.
+   *        DATACALL_AUTH_NONE        => PAP and CHAP is never performed.
+   *        DATACALL_AUTH_PAP         => PAP may be performed.
+   *        DATACALL_AUTH_CHAP        => CHAP may be performed.
+   *        DATACALL_AUTH_PAP_OR_CHAP => PAP / CHAP may be performed.
+   * @param pdptype
+   *        String containing PDP type to request. ("IP", "IPV6", ...)
+   */
+  setupDataCall: function (radioTech, apn, user, passwd, chappap, pdptype) {
+    let token = Buf.newParcel(REQUEST_SETUP_DATA_CALL);
+    Buf.writeUint32(7);
+    Buf.writeString(radioTech.toString());
+    Buf.writeString(DATACALL_PROFILE_DEFAULT.toString());
+    Buf.writeString(apn);
+    Buf.writeString(user);
+    Buf.writeString(passwd);
+    Buf.writeString(chappap.toString());
+    Buf.writeString(pdptype);
+    Buf.sendParcel();
+    return token;
+  },
+
+  /**
+   * Deactivate a data call.
+   *
+   * @param cid
+   *        String containing CID.
+   * @param reason
+   *        One of DATACALL_DEACTIVATE_* constants.
+   */
+  deactivateDataCall: function (cid, reason) {
+    let token = Buf.newParcel(REQUEST_DEACTIVATE_DATA_CALL);
+    Buf.writeUint32(2);
+    Buf.writeString(cid);
+    Buf.writeString(reason);
+    Buf.sendParcel();
+    return token;
+  },
+
+  /**
+   * Get a list of data calls.
+   */
+  getDataCallList: function getDataCallList() {
+    Buf.simpleRequest(REQUEST_DATA_CALL_LIST);
+  },
+
+  /**
+   * Get failure casue code for the most recently failed PDP context.
+   */
+  getFailCauseCode: function getFailCauseCode() {
+    Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE);
+  },
 
   /**
    * Handle incoming requests from the RIL. We find the method that
    * corresponds to the request type. Incidentally, the request type
    * _is_ the method name, so that's easy.
    */
 
   handleParcel: function handleParcel(request_type, length) {
@@ -944,17 +1014,20 @@ RIL[REQUEST_DTMF] = function REQUEST_DTM
 };
 RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS() {
   let messageRef = Buf.readUint32();
   let ackPDU = Buf.readString();
   let errorCode = Buf.readUint32();
   Phone.onSendSMS(messageRef, ackPDU, errorCode);
 };
 RIL[REQUEST_SEND_SMS_EXPECT_MORE] = null;
-RIL[REQUEST_SETUP_DATA_CALL] = null;
+RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL() {
+  let [cid, ifname, ipaddr, dns, gw] = Buf.readStringList();
+  Phone.onSetupDataCall(Buf.lastSolicitedToken, cid, ifname, ipaddr, dns, gw);
+};
 RIL[REQUEST_SIM_IO] = null;
 RIL[REQUEST_SEND_USSD] = null;
 RIL[REQUEST_CANCEL_USSD] = null;
 RIL[REQUEST_GET_CLIR] = null;
 RIL[REQUEST_SET_CLIR] = null;
 RIL[REQUEST_QUERY_CALL_FORWARD_STATUS] = null;
 RIL[REQUEST_SET_CALL_FORWARD] = null;
 RIL[REQUEST_QUERY_CALL_WAITING] = null;
@@ -968,17 +1041,19 @@ RIL[REQUEST_GET_IMEI] = function REQUEST
 };
 RIL[REQUEST_GET_IMEISV] = function REQUEST_GET_IMEISV() {
   let imeiSV = Buf.readString();
   Phone.onIMEISV(imeiSV);
 };
 RIL[REQUEST_ANSWER] = function REQUEST_ANSWER(length) {
   Phone.onAnswerCall();
 };
-RIL[REQUEST_DEACTIVATE_DATA_CALL] = null;
+RIL[REQUEST_DEACTIVATE_DATA_CALL] = function REQUEST_DEACTIVATE_DATA_CALL() {
+  Phone.onDeactivateDataCall(Buf.lastSolicitedToken);
+};
 RIL[REQUEST_QUERY_FACILITY_LOCK] = null;
 RIL[REQUEST_SET_FACILITY_LOCK] = null;
 RIL[REQUEST_CHANGE_BARRING_PASSWORD] = null;
 RIL[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE() {
   let response = Buf.readUint32List();
   Phone.onNetworkSelectionMode(response);
 };
 RIL[REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = null;
@@ -988,25 +1063,44 @@ RIL[REQUEST_DTMF_START] = function REQUE
   Phone.onStartTone();
 };
 RIL[REQUEST_DTMF_STOP] = function REQUEST_DTMF_STOP() {
   Phone.onStopTone();
 };
 RIL[REQUEST_BASEBAND_VERSION] = function REQUEST_BASEBAND_VERSION() {
   let version = Buf.readString();
   Phone.onBasebandVersion(version);
-},
+};
 RIL[REQUEST_SEPARATE_CONNECTION] = null;
 RIL[REQUEST_SET_MUTE] = function REQUEST_SET_MUTE(length) {
   Phone.onSetMute();
 };
 RIL[REQUEST_GET_MUTE] = null;
 RIL[REQUEST_QUERY_CLIP] = null;
 RIL[REQUEST_LAST_DATA_CALL_FAIL_CAUSE] = null;
-RIL[REQUEST_DATA_CALL_LIST] = null;
+RIL[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length) {
+  let datacalls = [];
+
+  if (!length) {
+    return;
+  }
+
+  let num = Buf.readUint32();
+  for (let i = 0; i < num; i++) {
+    datacalls.push({
+      cid: Buf.readUint32().toString(),
+      active: Buf.readUint32(),
+      type: Buf.readString(),
+      apn: Buf.readString(),
+      address: Buf.readString()
+    });
+  }
+
+  Phone.onDataCallList(datacalls);
+};
 RIL[REQUEST_RESET_RADIO] = null;
 RIL[REQUEST_OEM_HOOK_RAW] = null;
 RIL[REQUEST_OEM_HOOK_STRINGS] = null;
 RIL[REQUEST_SCREEN_STATE] = null;
 RIL[REQUEST_SET_SUPP_SVC_NOTIFICATION] = null;
 RIL[REQUEST_WRITE_SMS_TO_SIM] = null;
 RIL[REQUEST_DELETE_SMS_ON_SIM] = null;
 RIL[REQUEST_SET_BAND_MODE] = null;
@@ -1171,16 +1265,26 @@ let Phone = {
    */
   currentCalls: {},
 
   /**
    * Mute or unmute the radio.
    */
   _muted: true,
 
+  /**
+   * Existing data calls.
+   */
+  currentDataCalls: {},
+
+  /**
+   * Tracks active requests to the RIL concerning 3G data calls.
+   */
+  activeDataRequests: {},
+
   get muted() {
     return this._muted;
   },
 
   set muted(val) {
     val = Boolean(val);
     if (this._muted != val) {
       RIL.setMute(val);
@@ -1578,16 +1682,98 @@ let Phone = {
 
   onNewSMSOnSIM: function onNewSMSOnSIM(info) {
     //TODO
   },
 
   onAcknowledgeSMS: function onAcknowledgeSMS() {
   },
 
+  onSetupDataCall: function onSetupDataCall(token, cid, ifname, ipaddr,
+                                            dns, gw) {
+    let options = this.activeDataRequests[token];
+    delete this.activeDataRequests[token];
+
+    this.currentDataCalls[cid] = {
+      state: GECKO_DATACALL_STATE_CONNECTED,
+      cid: cid,
+      apn: options.apn,
+      ifname: ifname,
+      ipaddr: ipaddr,
+      dns: dns,
+      gw: gw,
+    };
+    this.sendDOMMessage({type: "datacallstatechange",
+                         state: GECKO_DATACALL_STATE_CONNECTED,
+                         cid: cid,
+                         apn: options.apn,
+                         ifname: ifname,
+                         ipaddr: ipaddr,
+                         dns: dns,
+                         gateway: gw});
+  },
+
+  onDeactivateDataCall: function onDeactivateDataCall(token) {
+    let options = this.activeDataRequests[token];
+    delete this.activeDataRequests[token];
+
+    let cid = options.cid;
+    if (!(cid in this.currentDataCalls)) {
+      return;
+    }
+
+    let apn = this.currentDataCalls[cid].apn;
+    delete this.currentDataCalls[cid];
+    this.sendDOMMessage({type: "datacallstatechange",
+                         state: GECKO_DATACALL_STATE_DISCONNECTED,
+                         cid: cid,
+                         apn: apn});
+  },
+
+  onDataCallList: function onDataCallList(datacalls) {
+    let currentDataCalls = this.currentDataCalls;
+
+    // Sync content of currentDataCalls and data call list.
+    for each (let datacall in datacalls) {
+      let {cid, apn} = datacall;
+
+      if (datacall.active != DATACALL_INACTIVE) {
+        // XXX: This should be followed up.
+        // datacall.active == DATACALL_ACTIVE_DOWN(1) for my device
+        if (!(cid in currentDataCalls)) {
+          let datacall = {state: GECKO_DATACALL_STATE_CONNECTED,
+                          cid: cid,
+                          apn: apn,
+                          ipaddr: datacall.address};
+          currentDataCalls[cid] = datacall;
+
+          this.sendDOMMessage({type: "datacallstatechange",
+                               state: GECKO_DATACALL_STATE_CONNECTED,
+                               cid: cid,
+                               apn: apn});
+        }
+      } else {                 // datacall.active == DATACALL_INACTIVE
+        if (cid in currentDataCalls) {
+          delete currentDataCalls[cid];
+          this.sendDOMMessage({type: "datacallstatechange",
+                               state: GECKO_DATACALL_STATE_DISCONNECTED,
+                               cid: cid,
+                               apn: apn});
+        }
+      }
+    }
+
+    let datacall_list = [];
+    for each (let datacall in this.currentDataCalls) {
+      datacall_list.push(datacall);
+    }
+    this.sendDOMMessage({type: "datacalllist",
+                         datacalls: datacall_list});
+  },
+
   /**
    * Outgoing requests to the RIL. These can be triggered from the
    * main thread via messages that look like this:
    *
    *   {type:  "methodName",
    *    extra: "parameters",
    *    go:    "here"}
    *
@@ -1725,16 +1911,64 @@ let Phone = {
     //TODO: the data encoding and length in octets should eventually be
     // computed on the mainthread and passed down to us.
     RIL.sendSMS(this.SMSC, options.number, options.body,
                 PDU_DCS_MSG_CODING_7BITS_ALPHABET, //TODO: hard-coded for now,
                 Math.ceil(options.body.length * 7 / 8)); //TODO: ditto
   },
 
   /**
+   * Setup a data call (PDP).
+   */
+  setupDataCall: function setupDataCall(options) {
+    if (DEBUG) debug("setupDataCall: " + JSON.stringify(options));
+
+    let token = RIL.setupDataCall(options.radioTech, options.apn,
+                                  options.user, options.passwd,
+                                  options.chappap, options.reason);
+    this.activeDataRequests[token] = options;
+    this.sendDOMMessage({type: "datacallstatechange",
+                         state: GECKO_DATACALL_STATE_CONNECTING,
+                         apn: options.apn});
+  },
+
+  /**
+   * Deactivate a data call (PDP).
+   */
+  deactivateDataCall: function deactivateDataCall(options) {
+    if (!(options.cid in this.currentDataCalls)) {
+      return;
+    }
+
+    let datacall = this.currentDataCalls[options.cid];
+    datacall.state = GECKO_DATACALL_STATE_DISCONNECTING;
+
+    let token = RIL.deactivateDataCall(options.cid, options.reason);
+    this.activeDataRequests[token] = options;
+    this.sendDOMMessage({type: "datacallstatechange",
+                         state: GECKO_DATACALL_STATE_DISCONNECTING,
+                         cid: options.cid,
+                         apn: datacall.apn});
+  },
+
+  /**
+   * Get the list of data calls.
+   */
+  getDataCallList: function getDataCallList(options) {
+    RIL.getDataCallList();
+  },
+
+  /**
+   * Get failure cause code for the last failed PDP context.
+   */
+  getFailCauseCode: function getFailCauseCode(options) {
+    RIL.getFailCauseCode();
+  },
+
+  /**
    * Handle incoming messages from the main UI thread.
    *
    * @param message
    *        Object containing the message. Messages are supposed
    */
   handleDOMMessage: function handleMessage(message) {
     if (DEBUG) debug("Received DOM message " + JSON.stringify(message));
     let method = this[message.type];
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -87,31 +87,53 @@ using namespace mozilla::xpconnect::memo
 
 // The stack limit the JS engine will check. Half the size of the
 // actual C stack, to be safe.
 #define WORKER_CONTEXT_NATIVE_STACK_LIMIT 128 * sizeof(size_t) * 1024
 
 // The maximum number of threads to use for workers, overridable via pref.
 #define MAX_WORKERS_PER_DOMAIN 10
 
+PR_STATIC_ASSERT(MAX_WORKERS_PER_DOMAIN >= 1);
+
 // The default number of seconds that close handlers will be allowed to run.
 #define MAX_SCRIPT_RUN_TIME_SEC 10
 
 // The number of seconds that idle threads can hang around before being killed.
 #define IDLE_THREAD_TIMEOUT_SEC 30
 
 // The maximum number of threads that can be idle at one time.
 #define MAX_IDLE_THREADS 20
 
 #define PREF_WORKERS_ENABLED "dom.workers.enabled"
 #define PREF_WORKERS_MAX_PER_DOMAIN "dom.workers.maxPerDomain"
 #define PREF_WORKERS_GCZEAL "dom.workers.gczeal"
 #define PREF_MAX_SCRIPT_RUN_TIME "dom.max_script_run_time"
 
-PR_STATIC_ASSERT(MAX_WORKERS_PER_DOMAIN >= 1);
+#define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
+#define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
+
+#define BROADCAST_ALL_WORKERS(_func, ...)                                      \
+  PR_BEGIN_MACRO                                                               \
+    AssertIsOnMainThread();                                                    \
+                                                                               \
+    nsAutoTArray<WorkerPrivate*, 100> workers;                                 \
+    {                                                                          \
+      MutexAutoLock lock(mMutex);                                              \
+                                                                               \
+      mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);        \
+    }                                                                          \
+                                                                               \
+    if (!workers.IsEmpty()) {                                                  \
+      AutoSafeJSContext cx;                                                    \
+      for (PRUint32 index = 0; index < workers.Length(); index++) {            \
+        workers[index]-> _func (cx, ##__VA_ARGS__);                            \
+      }                                                                        \
+    }                                                                          \
+  PR_END_MACRO
 
 namespace {
 
 const PRUint32 kNoIndex = PRUint32(-1);
 
 const PRUint32 kRequiredJSContextOptions =
   JSOPTION_DONT_REPORT_UNCAUGHT | JSOPTION_NO_SCRIPT_RVAL;
 
@@ -902,16 +924,25 @@ RuntimeService::Init()
   NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
 
   nsresult rv =
     obs->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mObserved = true;
 
+  if (NS_FAILED(obs->AddObserver(this, GC_REQUEST_OBSERVER_TOPIC, false))) {
+    NS_WARNING("Failed to register for GC request notifications!");
+  }
+
+  if (NS_FAILED(obs->AddObserver(this, MEMORY_PRESSURE_OBSERVER_TOPIC,
+                                 false))) {
+    NS_WARNING("Failed to register for memory pressure notifications!");
+  }
+
   for (PRUint32 index = 0; index < ArrayLength(gPrefsToWatch); index++) {
     if (NS_FAILED(Preferences::RegisterCallback(PrefCallback,
                                                 gPrefsToWatch[index], this))) {
       NS_WARNING("Failed to register pref callback?!");
     }
     PrefCallback(gPrefsToWatch[index], this);
   }
 
@@ -1014,17 +1045,17 @@ RuntimeService::Cleanup()
         }
       }
 
       // And make sure all their final messages have run and all their threads
       // have joined.
       while (mDomainMap.Count()) {
         MutexAutoUnlock unlock(mMutex);
 
-        if (NS_FAILED(NS_ProcessNextEvent(currentThread))) {
+        if (!NS_ProcessNextEvent(currentThread)) {
           NS_WARNING("Something bad happened!");
           break;
         }
       }
     }
   }
 
   if (mWindowMap.IsInitialized()) {
@@ -1032,16 +1063,25 @@ RuntimeService::Cleanup()
   }
 
   if (mObserved) {
     for (PRUint32 index = 0; index < ArrayLength(gPrefsToWatch); index++) {
       Preferences::UnregisterCallback(PrefCallback, gPrefsToWatch[index], this);
     }
 
     if (obs) {
+      if (NS_FAILED(obs->RemoveObserver(this, GC_REQUEST_OBSERVER_TOPIC))) {
+        NS_WARNING("Failed to unregister for GC request notifications!");
+      }
+
+      if (NS_FAILED(obs->RemoveObserver(this,
+                                        MEMORY_PRESSURE_OBSERVER_TOPIC))) {
+        NS_WARNING("Failed to unregister for memory pressure notifications!");
+      }
+
       nsresult rv =
         obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID);
       mObserved = NS_FAILED(rv);
     }
   }
 }
 
 // static
@@ -1190,90 +1230,61 @@ RuntimeService::NoteIdleThread(nsIThread
                                        nsITimer::TYPE_ONE_SHOT))) {
     NS_ERROR("Can't schedule timer!");
   }
 }
 
 void
 RuntimeService::UpdateAllWorkerJSContextOptions()
 {
-  AssertIsOnMainThread();
-
-  nsAutoTArray<WorkerPrivate*, 100> workers;
-  {
-    MutexAutoLock lock(mMutex);
-
-    mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
-  }
-
-  if (!workers.IsEmpty()) {
-    AutoSafeJSContext cx;
-    for (PRUint32 index = 0; index < workers.Length(); index++) {
-      workers[index]->UpdateJSContextOptions(cx, GetDefaultJSContextOptions());
-    }
-  }
+  BROADCAST_ALL_WORKERS(UpdateJSContextOptions, GetDefaultJSContextOptions());
 }
 
 void
 RuntimeService::UpdateAllWorkerJSRuntimeHeapSize()
 {
-  AssertIsOnMainThread();
-
-  nsAutoTArray<WorkerPrivate*, 100> workers;
-  {
-    MutexAutoLock lock(mMutex);
-
-    mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
-  }
-
-  if (!workers.IsEmpty()) {
-    AutoSafeJSContext cx;
-    for (PRUint32 index = 0; index < workers.Length(); index++) {
-      workers[index]->UpdateJSRuntimeHeapSize(cx,
-                                              GetDefaultJSRuntimeHeapSize());
-    }
-  }
+  BROADCAST_ALL_WORKERS(UpdateJSRuntimeHeapSize, GetDefaultJSRuntimeHeapSize());
 }
 
 #ifdef JS_GC_ZEAL
 void
 RuntimeService::UpdateAllWorkerGCZeal()
 {
-  AssertIsOnMainThread();
-
-  nsAutoTArray<WorkerPrivate*, 100> workers;
-  {
-    MutexAutoLock lock(mMutex);
-
-    mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
-  }
-
-  if (!workers.IsEmpty()) {
-    AutoSafeJSContext cx;
-    for (PRUint32 index = 0; index < workers.Length(); index++) {
-      workers[index]->UpdateGCZeal(cx, GetDefaultGCZeal());
-    }
-  }
+  BROADCAST_ALL_WORKERS(UpdateGCZeal, GetDefaultGCZeal());
 }
 #endif
 
+void
+RuntimeService::GarbageCollectAllWorkers(bool aShrinking)
+{
+  BROADCAST_ALL_WORKERS(GarbageCollect, aShrinking);
+}
+
 // nsISupports
 NS_IMPL_ISUPPORTS1(RuntimeService, nsIObserver)
 
 // nsIObserver
 NS_IMETHODIMP
 RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
                         const PRUnichar* aData)
 {
   AssertIsOnMainThread();
 
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)) {
     Cleanup();
     return NS_OK;
   }
+  if (!strcmp(aTopic, GC_REQUEST_OBSERVER_TOPIC)) {
+    GarbageCollectAllWorkers(false);
+    return NS_OK;
+  }
+  if (!strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
+    GarbageCollectAllWorkers(true);
+    return NS_OK;
+  }
 
   NS_NOTREACHED("Unknown observer topic!");
   return NS_OK;
 }
 
 RuntimeService::AutoSafeJSContext::AutoSafeJSContext(JSContext* aCx)
 : mContext(aCx ? aCx : GetSafeContext())
 {
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -228,16 +228,19 @@ public:
     AssertIsOnMainThread();
     sDefaultGCZeal = aGCZeal;
   }
 
   void
   UpdateAllWorkerGCZeal();
 #endif
 
+  void
+  GarbageCollectAllWorkers(bool aShrinking);
+
   class AutoSafeJSContext
   {
     JSContext* mContext;
 
   public:
     AutoSafeJSContext(JSContext* aCx = nsnull);
     ~AutoSafeJSContext();
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -53,16 +53,17 @@
 #include "nsITextToSubURI.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIXPConnect.h"
 
 #include "jsfriendapi.h"
 #include "jsdbgapi.h"
+#include "jsfriendapi.h"
 #include "jsprf.h"
 #include "js/MemoryMetrics.h"
 
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMJSUtils.h"
 #include "nsGUIEvent.h"
@@ -86,16 +87,22 @@
 #endif
 
 #include "WorkerInlines.h"
 
 #if 0 // Define to run GC more often.
 #define EXTRA_GC
 #endif
 
+// GC will run once every thirty seconds during normal execution.
+#define NORMAL_GC_TIMER_DELAY_MS 30000
+
+// GC will run five seconds after the last event is processed.
+#define IDLE_GC_TIMER_DELAY_MS 5000
+
 using mozilla::MutexAutoLock;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 using mozilla::dom::workers::exceptions::ThrowDOMExceptionForCode;
 using mozilla::xpconnect::memory::ReportJSRuntimeStats;
 
 USING_WORKERS_NAMESPACE
 
@@ -1413,16 +1420,53 @@ public:
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     aWorkerPrivate->UpdateGCZealInternal(aCx, mGCZeal);
     return true;
   }
 };
 #endif
 
+class GarbageCollectRunnable : public WorkerControlRunnable
+{
+protected:
+  bool mShrinking;
+  bool mCollectChildren;
+
+public:
+  GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking,
+                         bool aCollectChildren)
+  : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
+    mShrinking(aShrinking), mCollectChildren(aCollectChildren)
+  { }
+
+  bool
+  PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    // Silence bad assertions, this can be dispatched from either the main
+    // thread or the timer thread..
+    return true;
+  }
+
+  void
+  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+                bool aDispatchResult)
+  {
+    // Silence bad assertions, this can be dispatched from either the main
+    // thread or the timer thread..
+  }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    aWorkerPrivate->GarbageCollectInternal(aCx, mShrinking, mCollectChildren);
+    return true;
+  }
+};
+
 class CollectRuntimeStatsRunnable : public WorkerControlRunnable
 {
   typedef mozilla::Mutex Mutex;
   typedef mozilla::CondVar CondVar;
 
   Mutex mMutex;
   CondVar mCondVar;
   volatile bool mDone;
@@ -2167,16 +2211,28 @@ WorkerPrivateParent<Derived>::UpdateGCZe
     NS_WARNING("Failed to update worker gczeal!");
     JS_ClearPendingException(aCx);
   }
 }
 #endif
 
 template <class Derived>
 void
+WorkerPrivateParent<Derived>::GarbageCollect(JSContext* aCx, bool aShrinking)
+{
+  nsRefPtr<GarbageCollectRunnable> runnable =
+    new GarbageCollectRunnable(ParentAsWorkerPrivate(), aShrinking, true);
+  if (!runnable->Dispatch(aCx)) {
+    NS_WARNING("Failed to update worker heap size!");
+    JS_ClearPendingException(aCx);
+  }
+}
+
+template <class Derived>
+void
 WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
 {
   AssertIsOnMainThread();
 
   mBaseURI = aBaseURI;
 
   if (NS_FAILED(aBaseURI->GetSpec(mLocationInfo.mHref))) {
     mLocationInfo.mHref.Truncate();
@@ -2490,46 +2546,132 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
   {
     MutexAutoLock lock(mMutex);
     mJSContext = aCx;
 
     NS_ASSERTION(mStatus == Pending, "Huh?!");
     mStatus = Running;
   }
 
+  // We need a timer for GC. The basic plan is to run a normal (non-shrinking)
+  // GC periodically (NORMAL_GC_TIMER_DELAY_MS) while the worker is running.
+  // Once the worker goes idle we set a short (IDLE_GC_TIMER_DELAY_MS) timer to
+  // run a shrinking GC. If the worker receives more messages then the short
+  // timer is canceled and the periodic timer resumes.
+  nsCOMPtr<nsITimer> gcTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  if (!gcTimer) {
+    JS_ReportError(aCx, "Failed to create GC timer!");
+    return;
+  }
+
+  bool normalGCTimerRunning = false;
+
+  // We need to swap event targets below to get different types of GC behavior.
+  nsCOMPtr<nsIEventTarget> normalGCEventTarget;
+  nsCOMPtr<nsIEventTarget> idleGCEventTarget;
+
+  // We also need to track the idle GC event so that we don't confuse it with a
+  // generic event that should re-trigger the idle GC timer.
+  nsCOMPtr<nsIRunnable> idleGCEvent;
+  {
+    nsRefPtr<GarbageCollectRunnable> runnable =
+      new GarbageCollectRunnable(this, false, false);
+    normalGCEventTarget = new WorkerRunnableEventTarget(runnable);
+
+    runnable = new GarbageCollectRunnable(this, true, false);
+    idleGCEventTarget = new WorkerRunnableEventTarget(runnable);
+
+    idleGCEvent = runnable;
+  }
+
   mMemoryReporter = new WorkerMemoryReporter(this);
 
   if (NS_FAILED(NS_RegisterMemoryMultiReporter(mMemoryReporter))) {
     NS_WARNING("Failed to register memory reporter!");
     mMemoryReporter = nsnull;
   }
 
   for (;;) {
     Status currentStatus;
+    bool scheduleIdleGC;
+
     nsIRunnable* event;
     {
       MutexAutoLock lock(mMutex);
 
       while (!mControlQueue.Pop(event) && !mQueue.Pop(event)) {
         mCondVar.Wait();
       }
 
+      bool eventIsNotIdleGCEvent;
+      currentStatus = mStatus;
+
       {
         MutexAutoUnlock unlock(mMutex);
 
+        if (!normalGCTimerRunning &&
+            event != idleGCEvent &&
+            currentStatus <= Terminating) {
+          // Must always cancel before changing the timer's target.
+          if (NS_FAILED(gcTimer->Cancel())) {
+            NS_WARNING("Failed to cancel GC timer!");
+          }
+
+          if (NS_SUCCEEDED(gcTimer->SetTarget(normalGCEventTarget)) &&
+              NS_SUCCEEDED(gcTimer->InitWithFuncCallback(
+                                             DummyCallback, nsnull,
+                                             NORMAL_GC_TIMER_DELAY_MS,
+                                             nsITimer::TYPE_REPEATING_SLACK))) {
+            normalGCTimerRunning = true;
+          }
+          else {
+            JS_ReportError(aCx, "Failed to start normal GC timer!");
+          }
+        }
+
 #ifdef EXTRA_GC
         // Find GC bugs...
         JS_GC(aCx);
 #endif
 
+        // Keep track of whether or not this is the idle GC event.
+        eventIsNotIdleGCEvent = event != idleGCEvent;
+
         event->Run();
         NS_RELEASE(event);
       }
 
       currentStatus = mStatus;
+      scheduleIdleGC = mControlQueue.IsEmpty() &&
+                       mQueue.IsEmpty() &&
+                       eventIsNotIdleGCEvent;
+    }
+
+    // Take care of the GC timer. If we're starting the close sequence then we
+    // kill the timer once and for all. Otherwise we schedule the idle timeout
+    // if there are no more events.
+    if (currentStatus > Terminating || scheduleIdleGC) {
+      if (NS_SUCCEEDED(gcTimer->Cancel())) {
+        normalGCTimerRunning = false;
+      }
+      else {
+        NS_WARNING("Failed to cancel GC timer!");
+      }
+    }
+
+    if (scheduleIdleGC) {
+      if (NS_SUCCEEDED(gcTimer->SetTarget(idleGCEventTarget)) &&
+          NS_SUCCEEDED(gcTimer->InitWithFuncCallback(
+                                                    DummyCallback, nsnull,
+                                                    IDLE_GC_TIMER_DELAY_MS,
+                                                    nsITimer::TYPE_ONE_SHOT))) {
+      }
+      else {
+        JS_ReportError(aCx, "Failed to start idle GC timer!");
+      }
     }
 
 #ifdef EXTRA_GC
     // Find GC bugs...
     JS_GC(aCx);
 #endif
 
     if (currentStatus != Running && !HasActiveFeatures()) {
@@ -2547,16 +2689,21 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
         NS_ASSERTION(currentStatus == Killing, "Should have changed status!");
 #else
         currentStatus = Killing;
 #endif
       }
 
       // If we're supposed to die then we should exit the loop.
       if (currentStatus == Killing) {
+        // Always make sure the timer is canceled.
+        if (NS_FAILED(gcTimer->Cancel())) {
+          NS_WARNING("Failed to cancel the GC timer!");
+        }
+
         // Call this before unregistering the reporter as we may be racing with
         // the main thread.
         DisableMemoryReporter();
 
         if (mMemoryReporter) {
           if (NS_FAILED(NS_UnregisterMemoryMultiReporter(mMemoryReporter))) {
             NS_WARNING("Failed to unregister memory reporter!");
           }
@@ -3635,16 +3782,36 @@ WorkerPrivate::UpdateGCZealInternal(JSCo
   JS_SetGCZeal(aCx, aGCZeal, frequency, false);
 
   for (PRUint32 index = 0; index < mChildWorkers.Length(); index++) {
     mChildWorkers[index]->UpdateGCZeal(aCx, aGCZeal);
   }
 }
 #endif
 
+void
+WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
+                                      bool aCollectChildren)
+{
+  AssertIsOnWorkerThread();
+
+  if (aShrinking) {
+    JS_ShrinkingGC(aCx);
+  }
+  else {
+    JS_GC(aCx);
+  }
+
+  if (aCollectChildren) {
+    for (PRUint32 index = 0; index < mChildWorkers.Length(); index++) {
+      mChildWorkers[index]->GarbageCollect(aCx, aShrinking);
+    }
+  }
+}
+
 #ifdef DEBUG
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::AssertIsOnParentThread() const
 {
   if (GetParent()) {
     GetParent()->AssertIsOnWorkerThread();
   }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -313,16 +313,19 @@ public:
   void
   UpdateJSRuntimeHeapSize(JSContext* aCx, PRUint32 aJSRuntimeHeapSize);
 
 #ifdef JS_GC_ZEAL
   void
   UpdateGCZeal(JSContext* aCx, PRUint8 aGCZeal);
 #endif
 
+  void
+  GarbageCollect(JSContext* aCx, bool aShrinking);
+
   using events::EventTarget::GetEventListenerOnEventTarget;
   using events::EventTarget::SetEventListenerOnEventTarget;
 
   void
   QueueRunnable(WorkerRunnable* aRunnable)
   {
     AssertIsOnMainThread();
     mQueuedRunnables.AppendElement(aRunnable);
@@ -681,16 +684,20 @@ public:
   bool
   DisableMemoryReporter();
 
 #ifdef JS_GC_ZEAL
   void
   UpdateGCZealInternal(JSContext* aCx, PRUint8 aGCZeal);
 #endif
 
+  void
+  GarbageCollectInternal(JSContext* aCx, bool aShrinking,
+                         bool aCollectChildren);
+
   JSContext*
   GetJSContext() const
   {
     AssertIsOnWorkerThread();
     return mJSContext;
   }
 
 #ifdef DEBUG
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -312,16 +312,21 @@ private:
       return false;
     }
 
     jsval adaptor;
     if (!scope->GetEventListenerOnEventTarget(aCx, name + 2, &adaptor)) {
       return false;
     }
 
+    if (JSVAL_IS_VOID(adaptor)) {
+      *aVp = JSVAL_NULL;
+      return true;
+    }
+
     JS_ASSERT(JSVAL_IS_OBJECT(adaptor));
 
     jsval listener = js::GetFunctionNativeReserved(JSVAL_TO_OBJECT(adaptor),
                                                    SLOT_wrappedFunction);
 
     *aVp = listener;
     return true;
   }
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -16,19 +16,23 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
 
+#ifdef MOZ_WEBSMS_BACKEND
     <!-- WebSMS -->
     <uses-permission android:name="android.permission.SEND_SMS"/>
     <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+    <uses-permission android:name="android.permission.WRITE_SMS"/>
+    <uses-permission android:name="android.permission.READ_SMS"/>
+#endif
 
     <uses-feature android:name="android.hardware.location" android:required="false"/>
     <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
     <uses-feature android:name="android.hardware.touchscreen"/>
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-feature android:name="android.hardware.camera" android:required="false"/>
     <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -83,17 +83,16 @@ abstract public class GeckoApp
     public static GeckoApp mAppContext;
     public static boolean mFullscreen = false;
     public static File sGREDir = null;
     static Thread mLibLoadThread = null;
     public Handler mMainHandler;
     private IntentFilter mConnectivityFilter;
     private BroadcastReceiver mConnectivityReceiver;
     private BroadcastReceiver mBatteryReceiver;
-    private BroadcastReceiver mSmsReceiver;
 
     enum LaunchState {PreLaunch, Launching, WaitForDebugger,
                       Launched, GeckoRunning, GeckoExiting};
     private static LaunchState sLaunchState = LaunchState.PreLaunch;
     private static boolean sTryCatchAttached = false;
 
 
     static boolean checkLaunchState(LaunchState checkState) {
@@ -409,20 +408,21 @@ abstract public class GeckoApp
         mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mConnectivityReceiver = new GeckoConnectivityReceiver();
 
         IntentFilter batteryFilter = new IntentFilter();
         batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         mBatteryReceiver = new GeckoBatteryManager();
         registerReceiver(mBatteryReceiver, batteryFilter);
 
-        IntentFilter smsFilter = new IntentFilter();
-        smsFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
-        mSmsReceiver = new GeckoSmsManager();
-        registerReceiver(mSmsReceiver, smsFilter);
+        if (SmsManager.getInstance() != null) {
+            SmsManager.getInstance().init();
+        }
+
+        GeckoNetworkManager.getInstance().init();
 
         if (!checkAndSetLaunchState(LaunchState.PreLaunch,
                                     LaunchState.Launching))
             return;
 
         checkAndLaunchUpdate();
         mLibLoadThread = new Thread(new Runnable() {
             public void run() {
@@ -506,16 +506,17 @@ abstract public class GeckoApp
 
         // Whatever we do here should be fast, because we're blocking
         // the next activity from showing up until we finish.
 
         // onPause will be followed by either onResume or onStop.
         super.onPause();
 
         unregisterReceiver(mConnectivityReceiver);
+        GeckoNetworkManager.getInstance().stop();
     }
 
     @Override
     public void onResume()
     {
         Log.i(LOG_FILE_NAME, "resume");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
@@ -524,16 +525,17 @@ abstract public class GeckoApp
         super.onResume();
 
         // Just in case. Normally we start in onNewIntent
         if (checkLaunchState(LaunchState.PreLaunch) ||
             checkLaunchState(LaunchState.Launching))
             onNewIntent(getIntent());
 
         registerReceiver(mConnectivityReceiver, mConnectivityFilter);
+        GeckoNetworkManager.getInstance().start();
     }
 
     @Override
     public void onStop()
     {
         Log.i(LOG_FILE_NAME, "stop");
         // We're about to be stopped, potentially in preparation for
         // being destroyed.  We're killable after this point -- as I
@@ -572,19 +574,24 @@ abstract public class GeckoApp
     {
         Log.i(LOG_FILE_NAME, "destroy");
 
         // Tell Gecko to shutting down; we'll end up calling System.exit()
         // in onXreExit.
         if (isFinishing())
             GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_SHUTDOWN));
 
+        if (SmsManager.getInstance() != null) {
+            SmsManager.getInstance().shutdown();
+        }
+
+        GeckoNetworkManager.getInstance().stop();
+
         super.onDestroy();
 
-        unregisterReceiver(mSmsReceiver);
         unregisterReceiver(mBatteryReceiver);
     }
 
     @Override
     public void onConfigurationChanged(android.content.res.Configuration newConfig)
     {
         Log.i(LOG_FILE_NAME, "configuration changed");
         // nothing, just ignore
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -117,16 +117,28 @@ public class GeckoAppShell
     public static native void onChangeNetworkLinkStatus(String status);
     public static native void reportJavaCrash(String stack);
 
     public static native void processNextNativeEvent();
 
     public static native void notifyBatteryChange(double aLevel, boolean aCharging, double aRemainingTime);
 
     public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp);
+    public static native int  saveMessageInSentbox(String aReceiver, String aBody, long aTimestamp);
+    public static native void notifySmsSent(int aId, String aReceiver, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+    public static native void notifySmsDelivered(int aId, String aReceiver, String aBody, long aTimestamp);
+    public static native void notifySmsSendFailed(int aError, int aRequestId, long aProcessId);
+    public static native void notifyGetSms(int aId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+    public static native void notifyGetSmsFailed(int aError, int aRequestId, long aProcessId);
+    public static native void notifySmsDeleted(boolean aDeleted, int aRequestId, long aProcessId);
+    public static native void notifySmsDeleteFailed(int aError, int aRequestId, long aProcessId);
+    public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
+    public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+    public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
+    public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
 
     // A looper thread, accessed by GeckoAppShell.getHandler
     private static class LooperThread extends Thread {
         public SynchronousQueue<Handler> mHandlerQueue =
             new SynchronousQueue<Handler>();
         
         public void run() {
             Looper.prepare();
@@ -1684,28 +1696,96 @@ public class GeckoAppShell
     public static double[] getCurrentBatteryInformation() {
         return GeckoBatteryManager.getCurrentInformation();
     }
 
     /*
      * WebSMS related methods.
      */
     public static int getNumberOfMessagesForText(String aText) {
-        return GeckoSmsManager.getNumberOfMessagesForText(aText);
+        if (SmsManager.getInstance() == null) {
+            return 0;
+        }
+
+        return SmsManager.getInstance().getNumberOfMessagesForText(aText);
+    }
+
+    public static void sendMessage(String aNumber, String aMessage, int aRequestId, long aProcessId) {
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().send(aNumber, aMessage, aRequestId, aProcessId);
+    }
+
+    public static int saveSentMessage(String aRecipient, String aBody, long aDate) {
+        if (SmsManager.getInstance() == null) {
+            return -1;
+        }
+
+        return SmsManager.getInstance().saveSentMessage(aRecipient, aBody, aDate);
+    }
+
+    public static void getMessage(int aMessageId, int aRequestId, long aProcessId) {
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().getMessage(aMessageId, aRequestId, aProcessId);
     }
 
-    public static void sendMessage(String aNumber, String aMessage) {
-        GeckoSmsManager.send(aNumber, aMessage);
+    public static void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().deleteMessage(aMessageId, aRequestId, aProcessId);
+    }
+
+    public static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, aProcessId);
+    }
+
+    public static void getNextMessageInList(int aListId, int aRequestId, long aProcessId) {
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().getNextMessageInList(aListId, aRequestId, aProcessId);
+    }
+
+    public static void clearMessageList(int aListId) {
+        if (SmsManager.getInstance() == null) {
+            return;
+        }
+
+        SmsManager.getInstance().clearMessageList(aListId);
     }
 
     public static boolean isTablet() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
             Configuration config = GeckoApp.mAppContext.getResources().getConfiguration();
             // xlarge is defined by android as screens larger than 960dp x 720dp
             // and should include most devices ~7in and up.
             // http://developer.android.com/guide/practices/screens_support.html
             if ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE) {
                 return true;
             }
         }
         return false;
     }
+
+    public static double[] getCurrentNetworkInformation() {
+        return GeckoNetworkManager.getInstance().getCurrentInformation();
+    }
+
+    public static void enableNetworkNotifications() {
+        GeckoNetworkManager.getInstance().enableNotifications();
+    }
+
+    public static void disableNetworkNotifications() {
+        GeckoNetworkManager.getInstance().disableNotifications();
+    }
 }
--- a/embedding/android/GeckoEvent.java
+++ b/embedding/android/GeckoEvent.java
@@ -70,16 +70,20 @@ public class GeckoEvent {
     public static final int ACTIVITY_SHUTDOWN = 11;
     public static final int LOAD_URI = 12;
     public static final int SURFACE_CREATED = 13;
     public static final int SURFACE_DESTROYED = 14;
     public static final int GECKO_EVENT_SYNC = 15;
     public static final int ACTIVITY_START = 17;
     public static final int SAVE_STATE = 18;
     public static final int BROADCAST = 19;
+    public static final int VIEWPORT = 20;
+    public static final int TILE_SIZE = 21;
+    public static final int VISTITED = 22;
+    public static final int NETWORK_CHANGED = 23;
 
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
@@ -107,16 +111,19 @@ public class GeckoEvent {
     public int mKeyCode, mUnicodeChar;
     public int mOffset, mCount;
     public String mCharacters, mCharactersExtra;
     public int mRangeType, mRangeStyles;
     public int mRangeForeColor, mRangeBackColor;
     public Location mLocation;
     public Address  mAddress;
 
+    public double mBandwidth;
+    public boolean mCanBeMetered;
+
     public int mNativeWindow;
 
     public GeckoEvent() {
         mType = NATIVE_POKE;
     }
 
     public GeckoEvent(int evType) {
         mType = evType;
@@ -230,9 +237,15 @@ public class GeckoEvent {
         mCharacters = subject;
         mCharactersExtra = data;
     }
 
     public GeckoEvent(String uri) {
         mType = LOAD_URI;
         mCharacters = uri;
     }
+
+    public GeckoEvent(double bandwidth, boolean canBeMetered) {
+        mType = NETWORK_CHANGED;
+        mBandwidth = bandwidth;
+        mCanBeMetered = canBeMetered;
+    }
 }
new file mode 100644
--- /dev/null
+++ b/embedding/android/GeckoNetworkManager.java
@@ -0,0 +1,323 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import java.lang.Math;
+
+import android.util.Log;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+import android.telephony.TelephonyManager;
+
+/*
+ * A part of the work of GeckoNetworkManager is to give an estimation of the
+ * download speed of the current connection. For known to be fast connection, we
+ * simply use a predefined value (we don't care about being precise). For mobile
+ * connections, we sort them in groups (generations) and estimate the average
+ * real life download speed of that specific generation. This value comes from
+ * researches (eg. Wikipedia articles) or is simply an arbitrary estimation.
+ * Precision isn't important, we mostly need an order of magnitude.
+ *
+ * Each group is composed with networks represented by the constant from
+ * Android's ConnectivityManager and the description comming from the same
+ * class.
+ *
+ * 2G (15 bk/s):
+ * int NETWORK_TYPE_IDEN     Current network is iDen
+ * int NETWORK_TYPE_CDMA     Current network is CDMA: Either IS95A or IS95B
+ *
+ * 2.5G (60 kb/s)
+ * int NETWORK_TYPE_GPRS     Current network is GPRS
+ * int NETWORK_TYPE_1xRTT    Current network is 1xRTT
+ *
+ * 2.75G (200 kb/s)
+ * int NETWORK_TYPE_EDGE     Current network is EDGE
+ *
+ * 3G (300 kb/s)
+ * int NETWORK_TYPE_UMTS     Current network is UMTS
+ * int NETWORK_TYPE_EVDO_0   Current network is EVDO revision 0
+ *
+ * 3.5G (7 Mb/s)
+ * int NETWORK_TYPE_HSPA     Current network is HSPA
+ * int NETWORK_TYPE_HSDPA    Current network is HSDPA
+ * int NETWORK_TYPE_HSUPA    Current network is HSUPA
+ * int NETWORK_TYPE_EVDO_A   Current network is EVDO revision A
+ * int NETWORK_TYPE_EVDO_B   Current network is EVDO revision B
+ * int NETWORK_TYPE_EHRPD    Current network is eHRPD
+ *
+ * 3.75G (20 Mb/s)
+ * int NETWORK_TYPE_HSPAP    Current network is HSPA+
+ *
+ * 3.9G (50 Mb/s)
+ * int NETWORK_TYPE_LTE      Current network is LTE
+ */
+
+public class GeckoNetworkManager
+  extends BroadcastReceiver
+{
+  static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
+
+  static private final double  kDefaultBandwidth    = -1.0;
+  static private final boolean kDefaultCanBeMetered = false;
+
+  static private final double  kMaxBandwidth = 20.0;
+
+  static private final double  kNetworkSpeedEthernet = 20.0;           // 20 Mb/s
+  static private final double  kNetworkSpeedWifi     = 20.0;           // 20 Mb/s
+  static private final double  kNetworkSpeedWiMax    = 40.0;           // 40 Mb/s
+  static private final double  kNetworkSpeed_2_G     = 15.0 / 1024.0;  // 15 kb/s
+  static private final double  kNetworkSpeed_2_5_G   = 60.0 / 1024.0;  // 60 kb/s
+  static private final double  kNetworkSpeed_2_75_G  = 200.0 / 1024.0; // 200 kb/s
+  static private final double  kNetworkSpeed_3_G     = 300.0 / 1024.0; // 300 kb/s
+  static private final double  kNetworkSpeed_3_5_G   = 7.0;            // 7 Mb/s
+  static private final double  kNetworkSpeed_3_75_G  = 20.0;           // 20 Mb/s
+  static private final double  kNetworkSpeed_3_9_G   = 50.0;           // 50 Mb/s
+
+  private enum NetworkType {
+    NETWORK_NONE,
+    NETWORK_ETHERNET,
+    NETWORK_WIFI,
+    NETWORK_WIMAX,
+    NETWORK_2_G,    // 2G
+    NETWORK_2_5_G,  // 2.5G
+    NETWORK_2_75_G, // 2.75G
+    NETWORK_3_G,    // 3G
+    NETWORK_3_5_G,  // 3.5G
+    NETWORK_3_75_G, // 3.75G
+    NETWORK_3_9_G,  // 3.9G
+    NETWORK_UNKNOWN
+  }
+
+  private NetworkType  mNetworkType = NetworkType.NETWORK_NONE;
+  private IntentFilter mNetworkFilter = new IntentFilter();
+  // Whether the manager should be listening to Network Information changes.
+  private boolean mShouldBeListening = false;
+  // Whether the manager should notify Gecko that a change in Network
+  // Information happened.
+  private boolean mShouldNotify      = false;
+
+  public static GeckoNetworkManager getInstance() {
+    return sInstance;
+  }
+
+  @Override
+  public void onReceive(Context aContext, Intent aIntent) {
+    updateNetworkType();
+  }
+
+  public void init() {
+    mNetworkFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+
+    mNetworkType = getNetworkType();
+  }
+
+  public void start() {
+    mShouldBeListening = true;
+    updateNetworkType();
+
+    if (mShouldNotify) {
+      startListening();
+    }
+  }
+
+  private void startListening() {
+    GeckoApp.mAppContext.registerReceiver(sInstance, mNetworkFilter);
+  }
+
+  public void stop() {
+    mShouldBeListening = false;
+
+    if (mShouldNotify) {
+      stopListening();
+    }
+  }
+
+  private void stopListening() {
+    GeckoApp.mAppContext.unregisterReceiver(sInstance);
+  }
+
+  private void updateNetworkType() {
+    NetworkType previousNetworkType = mNetworkType;
+    mNetworkType = getNetworkType();
+
+    if (mNetworkType == previousNetworkType || !mShouldNotify) {
+      return;
+    }
+
+    GeckoAppShell.sendEventToGecko(new GeckoEvent(getNetworkSpeed(mNetworkType),
+                                                  isNetworkUsuallyMetered(mNetworkType)));
+  }
+
+  public double[] getCurrentInformation() {
+    return new double[] { getNetworkSpeed(mNetworkType),
+                          isNetworkUsuallyMetered(mNetworkType) ? 1.0 : 0.0 };
+  }
+
+  public void enableNotifications() {
+    // We set mShouldNotify *after* calling updateNetworkType() to make sure we
+    // don't notify an eventual change in mNetworkType.
+    updateNetworkType();
+    mShouldNotify = true;
+
+    if (mShouldBeListening) {
+      startListening();
+    }
+  }
+
+  public void disableNotifications() {
+    mShouldNotify = false;
+
+    if (mShouldBeListening) {
+      stopListening();
+    }
+  }
+
+  private static NetworkType getNetworkType() {
+    ConnectivityManager cm =
+      (ConnectivityManager)GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+    if (cm.getActiveNetworkInfo() == null) {
+      return NetworkType.NETWORK_NONE;
+    }
+
+    switch (cm.getActiveNetworkInfo().getType()) {
+      case ConnectivityManager.TYPE_ETHERNET:
+        return NetworkType.NETWORK_ETHERNET;
+      case ConnectivityManager.TYPE_WIFI:
+        return NetworkType.NETWORK_WIFI;
+      case ConnectivityManager.TYPE_WIMAX:
+        return NetworkType.NETWORK_WIMAX;
+      case ConnectivityManager.TYPE_MOBILE:
+        break; // We will handle sub-types after the switch.
+      default:
+        Log.w("GeckoNetworkManager", "Ignoring the current network type.");
+        return NetworkType.NETWORK_UNKNOWN;
+    }
+
+    TelephonyManager tm =
+      (TelephonyManager)GeckoApp.mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+    switch (tm.getNetworkType()) {
+      case TelephonyManager.NETWORK_TYPE_IDEN:
+      case TelephonyManager.NETWORK_TYPE_CDMA:
+        return NetworkType.NETWORK_2_G;
+      case TelephonyManager.NETWORK_TYPE_GPRS:
+      case TelephonyManager.NETWORK_TYPE_1xRTT:
+        return NetworkType.NETWORK_2_5_G;
+      case TelephonyManager.NETWORK_TYPE_EDGE:
+        return NetworkType.NETWORK_2_75_G;
+      case TelephonyManager.NETWORK_TYPE_UMTS:
+      case TelephonyManager.NETWORK_TYPE_EVDO_0:
+        return NetworkType.NETWORK_3_G;
+      case TelephonyManager.NETWORK_TYPE_HSPA:
+      case TelephonyManager.NETWORK_TYPE_HSDPA:
+      case TelephonyManager.NETWORK_TYPE_HSUPA:
+      case TelephonyManager.NETWORK_TYPE_EVDO_A:
+      case TelephonyManager.NETWORK_TYPE_EVDO_B:
+      case TelephonyManager.NETWORK_TYPE_EHRPD:
+        return NetworkType.NETWORK_3_5_G;
+      case TelephonyManager.NETWORK_TYPE_HSPAP:
+        return NetworkType.NETWORK_3_75_G;
+      case TelephonyManager.NETWORK_TYPE_LTE:
+        return NetworkType.NETWORK_3_9_G;
+      case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+      default:
+        Log.w("GeckoNetworkManager", "Connected to an unknown mobile network!");
+        return NetworkType.NETWORK_UNKNOWN;
+    }
+  }
+
+  private static double getNetworkSpeed(NetworkType aType) {
+    switch (aType) {
+      case NETWORK_NONE:
+        return 0.0;
+      case NETWORK_ETHERNET:
+        return kNetworkSpeedEthernet;
+      case NETWORK_WIFI:
+        return kNetworkSpeedWifi;
+      case NETWORK_WIMAX:
+        return kNetworkSpeedWiMax;
+      case NETWORK_2_G:
+        return kNetworkSpeed_2_G;
+      case NETWORK_2_5_G:
+        return kNetworkSpeed_2_5_G;
+      case NETWORK_2_75_G:
+        return kNetworkSpeed_2_75_G;
+      case NETWORK_3_G:
+        return kNetworkSpeed_3_G;
+      case NETWORK_3_5_G:
+        return kNetworkSpeed_3_5_G;
+      case NETWORK_3_75_G:
+        return kNetworkSpeed_3_75_G;
+      case NETWORK_3_9_G:
+        return kNetworkSpeed_3_9_G;
+      case NETWORK_UNKNOWN:
+      default:
+        return kDefaultBandwidth;
+    }
+  }
+
+  private static boolean isNetworkUsuallyMetered(NetworkType aType) {
+    switch (aType) {
+      case NETWORK_NONE:
+      case NETWORK_UNKNOWN:
+      case NETWORK_ETHERNET:
+      case NETWORK_WIFI:
+      case NETWORK_WIMAX:
+        return false;
+      case NETWORK_2_G:
+      case NETWORK_2_5_G:
+      case NETWORK_2_75_G:
+      case NETWORK_3_G:
+      case NETWORK_3_5_G:
+      case NETWORK_3_75_G:
+      case NETWORK_3_9_G:
+        return true;
+      default:
+        Log.e("GeckoNetworkManager", "Got an unexpected network type!");
+        return false;
+    }
+  }
+}
--- a/embedding/android/GeckoSmsManager.java
+++ b/embedding/android/GeckoSmsManager.java
@@ -33,36 +33,348 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package org.mozilla.gecko;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 
 import android.util.Log;
 
+import android.app.PendingIntent;
+import android.app.Activity;
+
+import android.database.Cursor;
+
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.ContentUris;
+
+import android.net.Uri;
 
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
 
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
 
+/**
+ * This class is returning unique ids for PendingIntent requestCode attribute.
+ * There are only |Integer.MAX_VALUE - Integer.MIN_VALUE| unique IDs available,
+ * and they wrap around.
+ */
+class PendingIntentUID
+{
+  static private int sUID = Integer.MIN_VALUE;
+
+  static public int generate() { return sUID++; }
+}
+
+/**
+ * The envelope class contains all information that are needed to keep track of
+ * a sent SMS.
+ */
+class Envelope
+{
+  enum SubParts {
+    SENT_PART,
+    DELIVERED_PART
+  }
+
+  protected int       mId;
+  protected int       mMessageId;
+  protected long      mMessageTimestamp;
+
+  /**
+   * Number of sent/delivered remaining parts.
+   * @note The array has much slots as SubParts items.
+   */
+  protected int[]     mRemainingParts;
+
+  /**
+   * Whether sending/delivering is currently failing.
+   * @note The array has much slots as SubParts items.
+   */
+  protected boolean[] mFailing;
+
+  /**
+   * Error type (only for sent).
+   */
+  protected int       mError;
+
+  public Envelope(int aId, int aParts) {
+    mId = aId;
+    mMessageId = -1;
+    mMessageTimestamp = 0;
+    mError = GeckoSmsManager.kNoError;
+
+    int size = Envelope.SubParts.values().length;
+    mRemainingParts = new int[size];
+    mFailing = new boolean[size];
+
+    for (int i=0; i<size; ++i) {
+      mRemainingParts[i] = aParts;
+      mFailing[i] = false;
+    }
+  }
+
+  public void decreaseRemainingParts(Envelope.SubParts aType) {
+    --mRemainingParts[aType.ordinal()];
+
+    if (mRemainingParts[SubParts.SENT_PART.ordinal()] >
+        mRemainingParts[SubParts.DELIVERED_PART.ordinal()]) {
+      Log.e("GeckoSmsManager", "Delivered more parts than we sent!?");
+    }
+  }
+
+  public boolean arePartsRemaining(Envelope.SubParts aType) {
+    return mRemainingParts[aType.ordinal()] != 0;
+  }
+
+  public void markAsFailed(Envelope.SubParts aType) {
+    mFailing[aType.ordinal()] = true;
+  }
+
+  public boolean isFailing(Envelope.SubParts aType) {
+    return mFailing[aType.ordinal()];
+  }
+
+  public int getMessageId() {
+    return mMessageId;
+  }
+
+  public void setMessageId(int aMessageId) {
+    mMessageId = aMessageId;
+  }
+
+  public long getMessageTimestamp() {
+    return mMessageTimestamp;
+  }
+
+  public void setMessageTimestamp(long aMessageTimestamp) {
+    mMessageTimestamp = aMessageTimestamp;
+  }
+
+  public int getError() {
+    return mError;
+  }
+
+  public void setError(int aError) {
+    mError = aError;
+  }
+}
+
+/**
+ * Postman class is a singleton that manages Envelope instances.
+ */
+class Postman
+{
+  public static final int kUnknownEnvelopeId = -1;
+
+  private static final Postman sInstance = new Postman();
+
+  private ArrayList<Envelope> mEnvelopes = new ArrayList<Envelope>(1);
+
+  private Postman() {}
+
+  public static Postman getInstance() {
+    return sInstance;
+  }
+
+  public int createEnvelope(int aParts) {
+    /*
+     * We are going to create the envelope in the first empty slot in the array
+     * list. If there is no empty slot, we create a new one.
+     */
+    int size = mEnvelopes.size();
+
+    for (int i=0; i<size; ++i) {
+      if (mEnvelopes.get(i) == null) {
+        mEnvelopes.set(i, new Envelope(i, aParts));
+        return i;
+      }
+    }
+
+    mEnvelopes.add(new Envelope(size, aParts));
+    return size;
+  }
+
+  public Envelope getEnvelope(int aId) {
+    if (aId < 0 || mEnvelopes.size() <= aId) {
+      Log.e("GeckoSmsManager", "Trying to get an unknown Envelope!");
+      return null;
+    }
+
+    Envelope envelope = mEnvelopes.get(aId);
+    if (envelope == null) {
+      Log.e("GeckoSmsManager", "Trying to get an empty Envelope!");
+    }
+
+    return envelope;
+  }
+
+  public void destroyEnvelope(int aId) {
+    if (aId < 0 || mEnvelopes.size() <= aId) {
+      Log.e("GeckoSmsManager", "Trying to destroy an unknown Envelope!");
+      return;
+    }
+
+    if (mEnvelopes.set(aId, null) == null) {
+      Log.e("GeckoSmsManager", "Trying to destroy an empty Envelope!");
+    }
+  }
+}
+
+class SmsIOThread extends Thread {
+  private final static SmsIOThread sInstance = new SmsIOThread();
+
+  private Handler mHandler;
+
+  public static SmsIOThread getInstance() {
+    return sInstance;
+  }
+
+  public boolean execute(Runnable r) {
+    return mHandler.post(r);
+  }
+
+  public void run() {
+    Looper.prepare();
+
+    mHandler = new Handler();
+
+    Looper.loop();
+  }
+}
+
+class MessagesListManager
+{
+  private static final MessagesListManager sInstance = new MessagesListManager();
+
+  public static MessagesListManager getInstance() {
+    return sInstance;
+  }
+
+  private ArrayList<Cursor> mCursors = new ArrayList<Cursor>(0);
+
+  public int add(Cursor aCursor) {
+    int size = mCursors.size();
+
+    for (int i=0; i<size; ++i) {
+      if (mCursors.get(i) == null) {
+        mCursors.set(i, aCursor);
+        return i;
+      }
+    }
+
+    mCursors.add(aCursor);
+    return size;
+  }
+
+  public Cursor get(int aId) {
+    if (aId < 0 || mCursors.size() <= aId) {
+      Log.e("GeckoSmsManager", "Trying to get an unknown list!");
+      return null;
+    }
+
+    Cursor cursor = mCursors.get(aId);
+    if (cursor == null) {
+      Log.e("GeckoSmsManager", "Trying to get an empty list!");
+    }
+
+    return cursor;
+  }
+
+  public void remove(int aId) {
+    if (aId < 0 || mCursors.size() <= aId) {
+      Log.e("GeckoSmsManager", "Trying to destroy an unknown list!");
+      return;
+    }
+
+    Cursor cursor = mCursors.set(aId, null);
+    if (cursor == null) {
+      Log.e("GeckoSmsManager", "Trying to destroy an empty list!");
+      return;
+    }
+
+    cursor.close();
+  }
+
+  public void clear() {
+    for (int i=0; i<mCursors.size(); ++i) {
+      Cursor c = mCursors.get(i);
+      if (c != null) {
+        c.close();
+      }
+    }
+
+    mCursors.clear();
+  }
+}
+
 public class GeckoSmsManager
   extends BroadcastReceiver
+  implements ISmsManager
 {
-  final static int kMaxMessageSize = 160;
+  public final static String ACTION_SMS_RECEIVED  = "android.provider.Telephony.SMS_RECEIVED";
+  public final static String ACTION_SMS_SENT      = "org.mozilla.gecko.SMS_SENT";
+  public final static String ACTION_SMS_DELIVERED = "org.mozilla.gecko.SMS_DELIVERED";
+
+  /*
+   * Make sure that the following error codes are in sync with |ErrorType| in:
+   * dom/sms/src/Types.h
+   * The error code are owned by the DOM.
+   */
+  public final static int kNoError       = 0;
+  public final static int kNoSignalError = 1;
+  public final static int kNotFoundError = 2;
+  public final static int kUnknownError  = 3;
+  public final static int kInternalError = 4;
+
+  private final static int kMaxMessageSize    = 160;
+
+  private final static Uri kSmsContentUri     = Uri.parse("content://sms");
+  private final static Uri kSmsSentContentUri = Uri.parse("content://sms/sent");
+
+  private final static int kSmsTypeInbox      = 1;
+  private final static int kSmsTypeSentbox    = 2;
+
+  /*
+   * Keep the following error codes in syng with |DeliveryState| in:
+   * dom/sms/src/Types.h
+   */
+  private final static int kDeliveryStateSent     = 0;
+  private final static int kDeliveryStateReceived = 1;
+  private final static int kDeliveryStateUnknown  = 2;
+  private final static int kDeliveryStateEndGuard = 3;
+
+  private final static String[] kRequiredMessageRows = new String[] { "_id", "address", "body", "date", "type" };
+
+  public void init() {
+    IntentFilter smsFilter = new IntentFilter();
+    smsFilter.addAction(GeckoSmsManager.ACTION_SMS_RECEIVED);
+    smsFilter.addAction(GeckoSmsManager.ACTION_SMS_SENT);
+    smsFilter.addAction(GeckoSmsManager.ACTION_SMS_DELIVERED);
+
+    GeckoApp.mAppContext.registerReceiver(this, smsFilter);
+
+    SmsIOThread.getInstance().start();
+  }
 
   @Override
   public void onReceive(Context context, Intent intent) {
-    if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
+    if (intent.getAction().equals(ACTION_SMS_RECEIVED)) {
       // TODO: Try to find the receiver number to be able to populate
       //       SmsMessage.receiver.
       // TODO: Get the id and the date from the stock app saved message.
       //       Using the stock app saved message require us to wait for it to
       //       be saved which can lead to race conditions.
 
       Bundle bundle = intent.getExtras();
 
@@ -74,35 +386,549 @@ public class GeckoSmsManager
 
       for (int i=0; i<pdus.length; ++i) {
         SmsMessage msg = SmsMessage.createFromPdu((byte[])pdus[i]);
 
         GeckoAppShell.notifySmsReceived(msg.getDisplayOriginatingAddress(),
                                         msg.getDisplayMessageBody(),
                                         System.currentTimeMillis());
       }
+
+      return;
+    }
+
+    if (intent.getAction().equals(ACTION_SMS_SENT) ||
+        intent.getAction().equals(ACTION_SMS_DELIVERED)) {
+      Bundle bundle = intent.getExtras();
+
+      if (bundle == null || !bundle.containsKey("envelopeId") ||
+          !bundle.containsKey("number") || !bundle.containsKey("message") ||
+          !bundle.containsKey("requestId") || !bundle.containsKey("processId")) {
+        Log.e("GeckoSmsManager", "Got an invalid ACTION_SMS_SENT/ACTION_SMS_DELIVERED!");
+        return;
+      }
+
+      int envelopeId = bundle.getInt("envelopeId");
+      Postman postman = Postman.getInstance();
+
+      Envelope envelope = postman.getEnvelope(envelopeId);
+      if (envelope == null) {
+        Log.e("GeckoSmsManager", "Got an invalid envelope id (or Envelope has been destroyed)!");
+        return;
+      }
+
+      Envelope.SubParts part = intent.getAction().equals(ACTION_SMS_SENT)
+                                 ? Envelope.SubParts.SENT_PART
+                                 : Envelope.SubParts.DELIVERED_PART;
+      envelope.decreaseRemainingParts(part);
+ 
+
+      if (getResultCode() != Activity.RESULT_OK) {
+        switch (getResultCode()) {
+          case SmsManager.RESULT_ERROR_NULL_PDU:
+            envelope.setError(kInternalError);
+            break;
+          case SmsManager.RESULT_ERROR_NO_SERVICE:
+          case SmsManager.RESULT_ERROR_RADIO_OFF:
+            envelope.setError(kNoSignalError);
+            break;
+          case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+          default:
+            envelope.setError(kUnknownError);
+            break;
+        }
+        envelope.markAsFailed(part);
+        Log.i("GeckoSmsManager", "SMS part sending failed!");
+      }
+
+      if (envelope.arePartsRemaining(part)) {
+        return;
+      }
+
+      if (envelope.isFailing(part)) {
+        if (part == Envelope.SubParts.SENT_PART) {
+          GeckoAppShell.notifySmsSendFailed(envelope.getError(),
+                                            bundle.getInt("requestId"),
+                                            bundle.getLong("processId"));
+          Log.i("GeckoSmsManager", "SMS sending failed!");
+        } else {
+          // It seems unlikely to get a result code for a failure to deliver.
+          // Even if, we don't want to do anything with this.
+          Log.e("GeckoSmsManager", "SMS failed to be delivered... is that even possible?");
+        }
+      } else {
+        if (part == Envelope.SubParts.SENT_PART) {
+          String number = bundle.getString("number");
+          String message = bundle.getString("message");
+          long timestamp = System.currentTimeMillis();
+
+          int id = GeckoAppShell.saveMessageInSentbox(number, message, timestamp);
+
+          GeckoAppShell.notifySmsSent(id, number, message, timestamp,
+                                      bundle.getInt("requestId"),
+                                      bundle.getLong("processId"));
+
+          envelope.setMessageId(id);
+          envelope.setMessageTimestamp(timestamp);
+
+          Log.i("GeckoSmsManager", "SMS sending was successfull!");
+        } else {
+          GeckoAppShell.notifySmsDelivered(envelope.getMessageId(),
+                                           bundle.getString("number"),
+                                           bundle.getString("message"),
+                                           envelope.getMessageTimestamp());
+          Log.i("GeckoSmsManager", "SMS succesfully delivered!");
+        }
+      }
+
+      // Destroy the envelope object only if the SMS has been sent and delivered.
+      if (!envelope.arePartsRemaining(Envelope.SubParts.SENT_PART) &&
+          !envelope.arePartsRemaining(Envelope.SubParts.DELIVERED_PART)) {
+        postman.destroyEnvelope(envelopeId);
+      }
+
+      return;
     }
   }
 
-  public static int getNumberOfMessagesForText(String aText) {
+  public int getNumberOfMessagesForText(String aText) {
     return SmsManager.getDefault().divideMessage(aText).size();
   }
 
-  public static void send(String aNumber, String aMessage) {
-    /*
-     * TODO:
-     * This is a basic send method that doesn't handle errors, doesn't listen to
-     * sent and received messages. It's only calling the send method.
-     */
+  public void send(String aNumber, String aMessage, int aRequestId, long aProcessId) {
+    int envelopeId = Postman.kUnknownEnvelopeId;
+
     try {
       SmsManager sm = SmsManager.getDefault();
 
+      Intent sentIntent = new Intent(ACTION_SMS_SENT);
+      Intent deliveredIntent = new Intent(ACTION_SMS_DELIVERED);
+
+      Bundle bundle = new Bundle();
+      bundle.putString("number", aNumber);
+      bundle.putString("message", aMessage);
+      bundle.putInt("requestId", aRequestId);
+      bundle.putLong("processId", aProcessId);
+
       if (aMessage.length() <= kMaxMessageSize) {
-        sm.sendTextMessage(aNumber, "", aMessage, null, null);
+        envelopeId = Postman.getInstance().createEnvelope(1);
+        bundle.putInt("envelopeId", envelopeId);
+
+        sentIntent.putExtras(bundle);
+        deliveredIntent.putExtras(bundle);
+
+        /*
+         * There are a few things to know about getBroadcast and pending intents:
+         * - the pending intents are in a shared pool maintained by the system;
+         * - each pending intent is identified by a token;
+         * - when a new pending intent is created, if it has the same token as
+         *   another intent in the pool, one of them has to be removed.
+         *
+         * To prevent having a hard time because of this situation, we give a
+         * unique id to all pending intents we are creating. This unique id is
+         * generated by GetPendingIntentUID().
+         */
+        PendingIntent sentPendingIntent =
+          PendingIntent.getBroadcast(GeckoApp.mAppContext,
+                                     PendingIntentUID.generate(), sentIntent,
+                                     PendingIntent.FLAG_CANCEL_CURRENT);
+
+        PendingIntent deliveredPendingIntent =
+          PendingIntent.getBroadcast(GeckoApp.mAppContext,
+                                     PendingIntentUID.generate(), deliveredIntent,
+                                     PendingIntent.FLAG_CANCEL_CURRENT);
+
+        sm.sendTextMessage(aNumber, "", aMessage,
+                           sentPendingIntent, deliveredPendingIntent);
       } else {
         ArrayList<String> parts = sm.divideMessage(aMessage);
-        sm.sendMultipartTextMessage(aNumber, "", parts, null, null);
+        envelopeId = Postman.getInstance().createEnvelope(parts.size());
+        bundle.putInt("envelopeId", envelopeId);
+
+        sentIntent.putExtras(bundle);
+        deliveredIntent.putExtras(bundle);
+
+        ArrayList<PendingIntent> sentPendingIntents =
+          new ArrayList<PendingIntent>(parts.size());
+        ArrayList<PendingIntent> deliveredPendingIntents =
+          new ArrayList<PendingIntent>(parts.size());
+
+        for (int i=0; i<parts.size(); ++i) {
+          sentPendingIntents.add(
+            PendingIntent.getBroadcast(GeckoApp.mAppContext,
+                                       PendingIntentUID.generate(), sentIntent,
+                                       PendingIntent.FLAG_CANCEL_CURRENT)
+          );
+
+          deliveredPendingIntents.add(
+            PendingIntent.getBroadcast(GeckoApp.mAppContext,
+                                       PendingIntentUID.generate(), deliveredIntent,
+                                       PendingIntent.FLAG_CANCEL_CURRENT)
+          );
+        }
+
+        sm.sendMultipartTextMessage(aNumber, "", parts, sentPendingIntents,
+                                    deliveredPendingIntents);
       }
     } catch (Exception e) {
-      Log.i("GeckoSmsManager", "Failed to send an SMS: ", e);
+      Log.e("GeckoSmsManager", "Failed to send an SMS: ", e);
+
+      if (envelopeId != Postman.kUnknownEnvelopeId) {
+        Postman.getInstance().destroyEnvelope(envelopeId);
+      }
+
+      GeckoAppShell.notifySmsSendFailed(kUnknownError, aRequestId, aProcessId);
+    }
+  }
+
+  public int saveSentMessage(String aRecipient, String aBody, long aDate) {
+    class IdTooHighException extends Exception { }
+
+    try {
+      ContentValues values = new ContentValues();
+      values.put("address", aRecipient);
+      values.put("body", aBody);
+      values.put("date", aDate);
+
+      ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+      Uri uri = cr.insert(kSmsSentContentUri, values);
+
+      long id = ContentUris.parseId(uri);
+
+      // The DOM API takes a 32bits unsigned int for the id. It's unlikely that
+      // we happen to need more than that but it doesn't cost to check.
+      if (id > Integer.MAX_VALUE) {
+        throw new IdTooHighException();
+      }
+
+      return (int)id;
+    } catch (IdTooHighException e) {
+      Log.e("GeckoSmsManager", "The id we received is higher than the higher allowed value.");
+      return -1;
+    } catch (Exception e) {
+      Log.e("GeckoSmsManager", "Something went wrong when trying to write a sent message: " + e);
+      return -1;
+    }
+  }
+
+  public void getMessage(int aMessageId, int aRequestId, long aProcessId) {
+    class GetMessageRunnable implements Runnable {
+      private int mMessageId;
+      private int mRequestId;
+      private long mProcessId;
+
+      GetMessageRunnable(int aMessageId, int aRequestId, long aProcessId) {
+        mMessageId = aMessageId;
+        mRequestId = aRequestId;
+        mProcessId = aProcessId;
+      }
+
+      @Override
+      public void run() {
+        class NotFoundException extends Exception { }
+        class UnmatchingIdException extends Exception { }
+        class TooManyResultsException extends Exception { }
+        class InvalidTypeException extends Exception { }
+
+        Cursor cursor = null;
+
+        try {
+          ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+          Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
+
+          cursor = cr.query(message, kRequiredMessageRows, null, null, null);
+          if (cursor == null || cursor.getCount() == 0) {
+            throw new NotFoundException();
+          }
+
+          if (cursor.getCount() != 1) {
+            throw new TooManyResultsException();
+          }
+
+          cursor.moveToFirst();
+
+          if (cursor.getInt(cursor.getColumnIndex("_id")) != mMessageId) {
+            throw new UnmatchingIdException();
+          }
+
+          int type = cursor.getInt(cursor.getColumnIndex("type"));
+          String sender = "";
+          String receiver = "";
+
+          if (type == kSmsTypeInbox) {
+            sender = cursor.getString(cursor.getColumnIndex("address"));
+          } else if (type == kSmsTypeSentbox) {
+            receiver = cursor.getString(cursor.getColumnIndex("address"));
+          } else {
+            throw new InvalidTypeException();
+          }
+
+          GeckoAppShell.notifyGetSms(cursor.getInt(cursor.getColumnIndex("_id")),
+                                     receiver, sender,
+                                     cursor.getString(cursor.getColumnIndex("body")),
+                                     cursor.getLong(cursor.getColumnIndex("date")),
+                                     mRequestId, mProcessId);
+        } catch (NotFoundException e) {
+          Log.i("GeckoSmsManager", "Message id " + mMessageId + " not found");
+          GeckoAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId, mProcessId);
+        } catch (UnmatchingIdException e) {
+          Log.e("GeckoSmsManager", "Requested message id (" + mMessageId +
+                                   ") is different from the one we got.");
+          GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId, mProcessId);
+        } catch (TooManyResultsException e) {
+          Log.e("GeckoSmsManager", "Get too many results for id " + mMessageId);
+          GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId, mProcessId);
+        } catch (InvalidTypeException e) {
+          Log.i("GeckoSmsManager", "Message has an invalid type, we ignore it.");
+          GeckoAppShell.notifyGetSmsFailed(kNotFoundError, mRequestId, mProcessId);
+        } catch (Exception e) {
+          Log.e("GeckoSmsManager", "Error while trying to get message: " + e);
+          GeckoAppShell.notifyGetSmsFailed(kUnknownError, mRequestId, mProcessId);
+        } finally {
+          if (cursor != null) {
+            cursor.close();
+          }
+        }
+      }
+    }
+
+    if (!SmsIOThread.getInstance().execute(new GetMessageRunnable(aMessageId, aRequestId, aProcessId))) {
+      Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
+      GeckoAppShell.notifyGetSmsFailed(kUnknownError, aRequestId, aProcessId);
+    }
+  }
+
+  public void deleteMessage(int aMessageId, int aRequestId, long aProcessId) {
+    class DeleteMessageRunnable implements Runnable {
+      private int mMessageId;
+      private int mRequestId;
+      private long mProcessId;
+
+      DeleteMessageRunnable(int aMessageId, int aRequestId, long aProcessId) {
+        mMessageId = aMessageId;
+        mRequestId = aRequestId;
+        mProcessId = aProcessId;
+      }
+
+      @Override
+      public void run() {
+        class TooManyResultsException extends Exception { }
+
+        try {
+          ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+          Uri message = ContentUris.withAppendedId(kSmsContentUri, mMessageId);
+
+          int count = cr.delete(message, null, null);
+
+          if (count > 1) {
+            throw new TooManyResultsException();
+          }
+
+          GeckoAppShell.notifySmsDeleted(count == 1, mRequestId, mProcessId);
+        } catch (TooManyResultsException e) {
+          Log.e("GeckoSmsManager", "Delete more than one message? " + e);
+          GeckoAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId, mProcessId);
+        } catch (Exception e) {
+          Log.e("GeckoSmsManager", "Error while trying to delete a message: " + e);
+          GeckoAppShell.notifySmsDeleteFailed(kUnknownError, mRequestId, mProcessId);
+        }
+      }
+    }
+
+    if (!SmsIOThread.getInstance().execute(new DeleteMessageRunnable(aMessageId, aRequestId, aProcessId))) {
+      Log.e("GeckoSmsManager", "Failed to add GetMessageRunnable to the SmsIOThread");
+      GeckoAppShell.notifySmsDeleteFailed(kUnknownError, aRequestId, aProcessId);
     }
   }
+
+  public void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
+    class CreateMessageListRunnable implements Runnable {
+      private long     mStartDate;
+      private long     mEndDate;
+      private String[] mNumbers;
+      private int      mNumbersCount;
+      private int      mDeliveryState;
+      private boolean  mReverse;
+      private int      mRequestId;
+      private long     mProcessId;
+
+      CreateMessageListRunnable(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId) {
+        mStartDate = aStartDate;
+        mEndDate = aEndDate;
+        mNumbers = aNumbers;
+        mNumbersCount = aNumbersCount;
+        mDeliveryState = aDeliveryState;
+        mReverse = aReverse;
+        mRequestId = aRequestId;
+        mProcessId = aProcessId;
+      }
+
+      @Override
+      public void run() {
+        class UnexpectedDeliveryStateException extends Exception { };
+        class InvalidTypeException extends Exception { }
+
+        Cursor cursor = null;
+        boolean closeCursor = true;
+
+        try {
+          // TODO: should use the |selectionArgs| argument in |ContentResolver.query()|.
+          ArrayList<String> restrictions = new ArrayList<String>();
+
+          if (mStartDate != 0) {
+            restrictions.add("date >= " + mStartDate);
+          }
+
+          if (mEndDate != 0) {
+            restrictions.add("date <= " + mEndDate);
+          }
+
+          if (mNumbersCount > 0) {
+            String numberRestriction = "address IN ('" + mNumbers[0] + "'";
+
+            for (int i=1; i<mNumbersCount; ++i) {
+              numberRestriction += ", '" + mNumbers[i] + "'";
+            }
+            numberRestriction += ")";
+
+            restrictions.add(numberRestriction);
+          }
+
+          if (mDeliveryState == kDeliveryStateUnknown) {
+            restrictions.add("type IN ('" + kSmsTypeSentbox + "', '" + kSmsTypeInbox + "')");
+          } else if (mDeliveryState == kDeliveryStateSent) {
+            restrictions.add("type = " + kSmsTypeSentbox);
+          } else if (mDeliveryState == kDeliveryStateReceived) {
+            restrictions.add("type = " + kSmsTypeInbox);
+          } else {
+            throw new UnexpectedDeliveryStateException();
+          }
+
+          String restrictionText = restrictions.size() > 0 ? restrictions.get(0) : "";
+
+          for (int i=1; i<restrictions.size(); ++i) {
+            restrictionText += " AND " + restrictions.get(i);
+          }
+
+          ContentResolver cr = GeckoApp.mAppContext.getContentResolver();
+          cursor = cr.query(kSmsContentUri, kRequiredMessageRows, restrictionText, null,
+                            mReverse ? "date DESC" : "date ASC");
+
+          if (cursor.getCount() == 0) {
+            GeckoAppShell.notifyNoMessageInList(mRequestId, mProcessId);
+            return;
+          }
+
+          cursor.moveToFirst();
+
+          int type = cursor.getInt(cursor.getColumnIndex("type"));
+          String sender = "";
+          String receiver = "";
+
+          if (type == kSmsTypeInbox) {
+            sender = cursor.getString(cursor.getColumnIndex("address"));
+          } else if (type == kSmsTypeSentbox) {
+            receiver = cursor.getString(cursor.getColumnIndex("address"));
+          } else {
+            throw new UnexpectedDeliveryStateException();
+          }
+
+          int listId = MessagesListManager.getInstance().add(cursor);
+          closeCursor = false;
+          GeckoAppShell.notifyListCreated(listId,
+                                          cursor.getInt(cursor.getColumnIndex("_id")),
+                                          receiver, sender,
+                                          cursor.getString(cursor.getColumnIndex("body")),
+                                          cursor.getLong(cursor.getColumnIndex("date")),
+                                          mRequestId, mProcessId);
+        } catch (UnexpectedDeliveryStateException e) {
+          Log.e("GeckoSmsManager", "Unexcepted delivery state type: " + e);
+          GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+        } catch (Exception e) {
+          Log.e("GeckoSmsManager", "Error while trying to create a message list cursor: " + e);
+          GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+        } finally {
+          // Close the cursor if MessagesListManager isn't taking care of it.
+          // We could also just check if it is in the MessagesListManager list but
+          // that would be less efficient.
+          if (cursor != null && closeCursor) {
+            cursor.close();
+          }
+        }
+      }
+    }
+
+    if (!SmsIOThread.getInstance().execute(new CreateMessageListRunnable(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId, aProcessId))) {
+      Log.e("GeckoSmsManager", "Failed to add CreateMessageListRunnable to the SmsIOThread");
+      GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId, aProcessId);
+    }
+  }
+
+  public void getNextMessageInList(int aListId, int aRequestId, long aProcessId) {
+    class GetNextMessageInListRunnable implements Runnable {
+      private int mListId;
+      private int mRequestId;
+      private long mProcessId;
+
+      GetNextMessageInListRunnable(int aListId, int aRequestId, long aProcessId) {
+        mListId = aListId;
+        mRequestId = aRequestId;
+        mProcessId = aProcessId;
+      }
+
+      @Override
+      public void run() {
+        class UnexpectedDeliveryStateException extends Exception { };
+
+        try {
+          Cursor cursor = MessagesListManager.getInstance().get(mListId);
+
+          if (!cursor.moveToNext()) {
+            MessagesListManager.getInstance().remove(mListId);
+            GeckoAppShell.notifyNoMessageInList(mRequestId, mProcessId);
+            return;
+          }
+
+          int type = cursor.getInt(cursor.getColumnIndex("type"));
+          String sender = "";
+          String receiver = "";
+
+          if (type == kSmsTypeInbox) {
+            sender = cursor.getString(cursor.getColumnIndex("address"));
+          } else if (type == kSmsTypeSentbox) {
+            receiver = cursor.getString(cursor.getColumnIndex("address"));
+          } else {
+            throw new UnexpectedDeliveryStateException();
+          }
+
+          int listId = MessagesListManager.getInstance().add(cursor);
+          GeckoAppShell.notifyGotNextMessage(cursor.getInt(cursor.getColumnIndex("_id")),
+                                             receiver, sender,
+                                             cursor.getString(cursor.getColumnIndex("body")),
+                                             cursor.getLong(cursor.getColumnIndex("date")),
+                                             mRequestId, mProcessId);
+        } catch (UnexpectedDeliveryStateException e) {
+          Log.e("GeckoSmsManager", "Unexcepted delivery state type: " + e);
+          GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+        } catch (Exception e) {
+          Log.e("GeckoSmsManager", "Error while trying to get the next message of a list: " + e);
+          GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, mRequestId, mProcessId);
+        }
+      }
+    }
+
+    if (!SmsIOThread.getInstance().execute(new GetNextMessageInListRunnable(aListId, aRequestId, aProcessId))) {
+      Log.e("GeckoSmsManager", "Failed to add GetNextMessageInListRunnable to the SmsIOThread");
+      GeckoAppShell.notifyReadingMessageListFailed(kUnknownError, aRequestId, aProcessId);
+    }
+  }
+
+  public void clearMessageList(int aListId) {
+    MessagesListManager.getInstance().remove(aListId);
+  }
+
+  public void shutdown() {
+    GeckoApp.mAppContext.unregisterReceiver(this);
+
+    SmsIOThread.getInstance().interrupt();
+    MessagesListManager.getInstance().clear();
+  }
 }
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -50,25 +50,30 @@ JAVAFILES = \
   GeckoAppShell.java \
   GeckoConnectivityReceiver.java \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   AlertNotification.java \
   SurfaceInfo.java \
   GeckoBatteryManager.java \
-  GeckoSmsManager.java \
   VideoPlayer.java \
+  GeckoNetworkManager.java \
   $(NULL)
 
+ifdef MOZ_WEBSMS_BACKEND
+JAVAFILES += GeckoSmsManager.java
+endif
+
 PROCESSEDJAVAFILES = \
   App.java \
   Restarter.java \
   NotificationHandler.java \
   LauncherShortcuts.java \
+  SmsManager.java \
   $(NULL)
 
 
 ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
 MIN_CPU_VERSION=7
 else
 MIN_CPU_VERSION=5
 endif
new file mode 100644
--- /dev/null
+++ b/embedding/android/SmsManager.java.in
@@ -0,0 +1,71 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+#ifdef MOZ_WEBSMS_BACKEND
+import org.mozilla.gecko.GeckoSmsManager;
+#endif
+
+class SmsManager
+{
+  static private ISmsManager sInstance = null;
+
+  static public ISmsManager getInstance() {
+#ifdef MOZ_WEBSMS_BACKEND
+    if (sInstance == null) {
+      sInstance = new GeckoSmsManager();
+    }
+#endif
+    return sInstance;
+  }
+}
+
+interface ISmsManager
+{
+  public void init();
+  public void shutdown();
+
+  public int getNumberOfMessagesForText(String aText);
+  public void send(String aNumber, String aMessage, int aRequestId, long aProcessId);
+  public int saveSentMessage(String aRecipient, String aBody, long aDate);
+  public void getMessage(int aMessageId, int aRequestId, long aProcessId);
+  public void deleteMessage(int aMessageId, int aRequestId, long aProcessId);
+  public void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId, long aProcessId);
+  public void getNextMessageInList(int aListId, int aRequestId, long aProcessId);
+  public void clearMessageList(int aListId);
+}
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -268,16 +268,34 @@ protected:
 
   void GetCurrentInformationInternal(BatteryInformation* aInfo) {
     PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
   }
 };
 
 static BatteryObserversManager sBatteryObservers;
 
+class NetworkObserversManager : public ObserversManager<NetworkInformation>
+{
+protected:
+  void EnableNotifications() {
+    PROXY_IF_SANDBOXED(EnableNetworkNotifications());
+  }
+
+  void DisableNotifications() {
+    PROXY_IF_SANDBOXED(DisableNetworkNotifications());
+  }
+
+  void GetCurrentInformationInternal(NetworkInformation* aInfo) {
+    PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
+  }
+};
+
+static NetworkObserversManager sNetworkObservers;
+
 void
 RegisterBatteryObserver(BatteryObserver* aObserver)
 {
   AssertMainThread();
   sBatteryObservers.AddObserver(aObserver);
 }
 
 void
@@ -321,10 +339,38 @@ double GetScreenBrightness()
 }
 
 void SetScreenBrightness(double brightness)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
 }
 
+void
+RegisterNetworkObserver(NetworkObserver* aObserver)
+{
+  AssertMainThread();
+  sNetworkObservers.AddObserver(aObserver);
+}
+
+void
+UnregisterNetworkObserver(NetworkObserver* aObserver)
+{
+  AssertMainThread();
+  sNetworkObservers.RemoveObserver(aObserver);
+}
+
+void
+GetCurrentNetworkInformation(NetworkInformation* aInfo)
+{
+  AssertMainThread();
+  *aInfo = sNetworkObservers.GetCurrentInformation();
+}
+
+void
+NotifyNetworkChange(const NetworkInformation& aInfo)
+{
+  sNetworkObservers.CacheInformation(aInfo);
+  sNetworkObservers.BroadcastCachedInformation();
+}
+
 } // namespace hal
 } // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -41,16 +41,17 @@
 #define mozilla_Hal_h 1
 
 #include "mozilla/hal_sandbox/PHal.h"
 #include "base/basictypes.h"
 #include "mozilla/Types.h"
 #include "nsTArray.h"
 #include "prlog.h"
 #include "mozilla/dom/battery/Types.h"
+#include "mozilla/dom/network/Types.h"
 
 /*
  * Hal.h contains the public Hal API.
  *
  * By default, this file defines its functions in the hal namespace, but if
  * MOZ_HAL_NAMESPACE is defined, we'll define our functions in that namespace.
  *
  * This is used by HalImpl.h and HalSandbox.h, which define copies of all the
@@ -163,16 +164,39 @@ double GetScreenBrightness();
  *
  * Note that we may reduce the resolution of the given brightness value before
  * sending it to the screen.  Therefore if you call SetScreenBrightness(x)
  * followed by GetScreenBrightness(), the value returned by
  * GetScreenBrightness() may not be exactly x.
  */
 void SetScreenBrightness(double brightness);
 
+/**
+ * Inform the network backend there is a new network observer.
+ * @param aNetworkObserver The observer that should be added.
+ */
+void RegisterNetworkObserver(NetworkObserver* aNetworkObserver);
+
+/**
+ * Inform the network backend a network observer unregistered.
+ * @param aNetworkObserver The observer that should be removed.
+ */
+void UnregisterNetworkObserver(NetworkObserver* aNetworkObserver);
+
+/**
+ * Returns the current network information.
+ */
+void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
+
+/**
+ * Notify of a change in the network state.
+ * @param aNetworkInfo The new network information.
+ */
+void NotifyNetworkChange(const hal::NetworkInformation& aNetworkInfo);
+
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #ifdef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_HAL_NAMESPACE
 #endif
 
--- a/hal/HalInternal.h
+++ b/hal/HalInternal.h
@@ -62,12 +62,22 @@ namespace MOZ_HAL_NAMESPACE {
  */
 void EnableBatteryNotifications();
 
 /**
  * Disables battery notifications from the backend.
  */
 void DisableBatteryNotifications();
 
+/**
+ * Enables network notifications from the backend.
+ */
+void EnableNetworkNotifications();
+
+/**
+ * Disables network notifications from the backend.
+ */
+void DisableNetworkNotifications();
+
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #endif  // mozilla_HalInternal_h
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -34,16 +34,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Hal.h"
 #include "HalImpl.h"
 #include "WindowIdentifier.h"
 #include "AndroidBridge.h"
+#include "mozilla/dom/network/Constants.h"
 
 using mozilla::hal::WindowIdentifier;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32> &pattern, const WindowIdentifier &)
@@ -134,11 +135,44 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+void
+EnableNetworkNotifications()
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->EnableNetworkNotifications();
+}
+
+void
+DisableNetworkNotifications()
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->DisableNetworkNotifications();
+}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->GetCurrentNetworkInformation(aNetworkInfo);
+}
+
 } // hal_impl
 } // mozilla
 
--- a/hal/fallback/FallbackHal.cpp
+++ b/hal/fallback/FallbackHal.cpp
@@ -34,16 +34,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Hal.h"
 #include "mozilla/dom/battery/Constants.h"
+#include "mozilla/dom/network/Constants.h"
 
 using mozilla::hal::WindowIdentifier;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32>& pattern, const hal::WindowIdentifier &)
@@ -84,10 +85,25 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+void
+EnableNetworkNotifications()
+{}
+
+void
+DisableNetworkNotifications()
+{}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+  aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
+  aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+}
+
 } // hal_impl
 } // namespace mozilla
--- a/hal/linux/LinuxHal.cpp
+++ b/hal/linux/LinuxHal.cpp
@@ -31,16 +31,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Hal.h"
+#include "mozilla/dom/network/Constants.h"
 
 #ifndef MOZ_ENABLE_DBUS
 #include <mozilla/dom/battery/Constants.h>
 #endif // !MOZ_ENABLE_DBUS
 
 namespace mozilla {
 namespace hal_impl {
 
@@ -85,11 +86,26 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+void
+EnableNetworkNotifications()
+{}
+
+void
+DisableNetworkNotifications()
+{}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+  aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
+  aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+}
+
 } // hal_impl
 } // mozilla
 
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -45,33 +45,46 @@ namespace mozilla {
 namespace hal {
   struct BatteryInformation {
     double level;
     bool   charging;
     double remainingTime;
   };
 }
 
+namespace hal {
+  struct NetworkInformation {
+    double bandwidth;
+    bool   canBeMetered;
+  };
+}
+
 namespace hal_sandbox {
 
 sync protocol PHal {
     manager PContent;
 
 child:
     NotifyBatteryChange(BatteryInformation aBatteryInfo);
+    NotifyNetworkChange(NetworkInformation aNetworkInfo);
 
 parent:
     Vibrate(uint32[] pattern, uint64[] id, PBrowser browser);
     CancelVibrate(uint64[] id, PBrowser browser);
 
     EnableBatteryNotifications();
     DisableBatteryNotifications();
     sync GetCurrentBatteryInformation()
       returns (BatteryInformation aBatteryInfo);
 
+    EnableNetworkNotifications();
+    DisableNetworkNotifications();
+    sync GetCurrentNetworkInformation()
+      returns (NetworkInformation aNetworkInfo);
+
     sync GetScreenEnabled() returns (bool enabled);
     SetScreenEnabled(bool enabled);
 
     sync GetScreenBrightness() returns (double brightness);
     SetScreenBrightness(double brightness);
 
     __delete__();
 };
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -39,16 +39,17 @@
 
 #include "Hal.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/battery/Types.h"
+#include "mozilla/dom/network/Types.h"
 #include "mozilla/Observer.h"
 #include "mozilla/unused.h"
 #include "WindowIdentifier.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 
@@ -100,16 +101,34 @@ DisableBatteryNotifications()
 }
 
 void
 GetCurrentBatteryInformation(BatteryInformation* aBatteryInfo)
 {
   Hal()->SendGetCurrentBatteryInformation(aBatteryInfo);
 }
 
+void
+EnableNetworkNotifications()
+{
+  Hal()->SendEnableNetworkNotifications();
+}
+
+void
+DisableNetworkNotifications()
+{
+  Hal()->SendDisableNetworkNotifications();
+}
+
+void
+GetCurrentNetworkInformation(NetworkInformation* aNetworkInfo)
+{
+  Hal()->SendGetCurrentNetworkInformation(aNetworkInfo);
+}
+
 bool
 GetScreenEnabled()
 {
   bool enabled = false;
   Hal()->SendGetScreenEnabled(&enabled);
   return enabled;
 }
 
@@ -129,17 +148,19 @@ GetScreenBrightness()
 
 void
 SetScreenBrightness(double brightness)
 {
   Hal()->SendSetScreenBrightness(brightness);
 }
 
 class HalParent : public PHalParent
-                , public BatteryObserver {
+                , public BatteryObserver
+                , public NetworkObserver
+{
 public:
   NS_OVERRIDE virtual bool
   RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
               const InfallibleTArray<uint64> &id,
               PBrowserParent *browserParent)
   {
     // Check whether browserParent is active.  We should have already
     // checked that the corresponding window is active, but this check
@@ -193,16 +214,38 @@ public:
     return true;
   }
 
   void Notify(const BatteryInformation& aBatteryInfo) {
     unused << SendNotifyBatteryChange(aBatteryInfo);
   }
 
   NS_OVERRIDE virtual bool
+  RecvEnableNetworkNotifications() {
+    hal::RegisterNetworkObserver(this);
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvDisableNetworkNotifications() {
+    hal::UnregisterNetworkObserver(this);
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvGetCurrentNetworkInformation(NetworkInformation* aNetworkInfo) {
+    hal::GetCurrentNetworkInformation(aNetworkInfo);
+    return true;
+  }
+
+  void Notify(const NetworkInformation& aNetworkInfo) {
+    unused << SendNotifyNetworkChange(aNetworkInfo);
+  }
+
+  NS_OVERRIDE virtual bool
   RecvGetScreenEnabled(bool *enabled)
   {
     *enabled = hal::GetScreenEnabled();
     return true;
   }
 
   NS_OVERRIDE virtual bool
   RecvSetScreenEnabled(const bool &enabled)
@@ -228,16 +271,22 @@ public:
 
 class HalChild : public PHalChild {
 public:
   NS_OVERRIDE virtual bool
   RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) {
     hal::NotifyBatteryChange(aBatteryInfo);
     return true;
   }
+
+  NS_OVERRIDE virtual bool
+  RecvNotifyNetworkChange(const NetworkInformation& aNetworkInfo) {
+    hal::NotifyNetworkChange(aNetworkInfo);
+    return true;
+  }
 };
 
 PHalChild* CreateHalChild() {
   return new HalChild();
 }
 
 PHalParent* CreateHalParent() {
   return new HalParent();
--- a/hal/windows/WindowsHal.cpp
+++ b/hal/windows/WindowsHal.cpp
@@ -31,16 +31,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Hal.h"
+#include "mozilla/dom/network/Constants.h"
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32>& pattern, const hal::WindowIdentifier &)
 {}
 
@@ -63,10 +64,25 @@ GetScreenBrightness()
 {
   return 1;
 }
 
 void
 SetScreenBrightness(double brightness)
 {}
 
+void
+EnableNetworkNotifications()
+{}
+
+void
+DisableNetworkNotifications()
+{}
+
+void
+GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+  aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
+  aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+}
+
 } // hal_impl
 } // mozilla
--- a/intl/uconv/src/nsCharsetConverterManager.cpp
+++ b/intl/uconv/src/nsCharsetConverterManager.cpp
@@ -233,17 +233,16 @@ nsCharsetConverterManager::GetList(const
                                    const nsACString& aPrefix,
                                    nsIUTF8StringEnumerator** aResult)
 {
   if (aResult == NULL) 
     return NS_ERROR_NULL_POINTER;
   *aResult = NULL;
 
   nsresult rv;
-  nsCAutoString alias;
 
   nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
   if (NS_FAILED(rv))
     return rv;
 
   nsTArray<nsCString>* array = new nsTArray<nsCString>;
   if (!array)
     return NS_ERROR_OUT_OF_MEMORY;
@@ -257,28 +256,23 @@ nsCharsetConverterManager::GetList(const
     nsCOMPtr<nsISupports> supports;
     if (NS_FAILED(enumerator->GetNext(getter_AddRefs(supports))))
       continue;
     
     nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports);
     if (!supStr)
       continue;
 
-    nsCAutoString fullName(aPrefix);
-    
     nsCAutoString name;
     if (NS_FAILED(supStr->GetData(name)))
       continue;
 
-    fullName += name;
-    rv = GetCharsetAlias(fullName.get(), alias);
-    if (NS_FAILED(rv)) 
-      continue;
-
-    rv = array->AppendElement(alias) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+    nsCAutoString fullName(aPrefix);
+    fullName.Append(name);
+    NS_ENSURE_TRUE(array->AppendElement(fullName), NS_ERROR_OUT_OF_MEMORY);
   }
     
   return NS_NewAdoptingUTF8StringEnumerator(aResult, array);
 }
 
 // we should change the interface so that we can just pass back a enumerator!
 NS_IMETHODIMP
 nsCharsetConverterManager::GetDecoderList(nsIUTF8StringEnumerator ** aResult)
@@ -312,17 +306,16 @@ nsCharsetConverterManager::GetCharsetAli
   NS_ENSURE_ARG_POINTER(aCharset);
 
   // We try to obtain the preferred name for this charset from the charset 
   // aliases.
   nsresult rv;
   nsCOMPtr<nsICharsetAlias> csAlias(do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAutoString pref;
   rv = csAlias->GetPreferred(nsDependentCString(aCharset), aResult);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
new file mode 100644
--- /dev/null
+++ b/intl/uconv/tests/unit/test_bug718500.js
@@ -0,0 +1,219 @@
+var detectList = [
+  "chardet.universal_charset_detector",
+  "chardet.ja_parallel_state_machine",
+  "chardet.ko_parallel_state_machine",
+  "chardet.zhtw_parallel_state_machine",
+  "chardet.zhcn_parallel_state_machine",
+  "chardet.zh_parallel_state_machine",
+  "chardet.cjk_parallel_state_machine",
+  "chardet.off",
+  "chardet.ruprob",
+  "chardet.ukprob",
+];
+
+var encoderList = [
+  "ISO-8859-1",
+  "windows-1252",
+  "x-mac-roman",
+  "UTF-8",
+  "us-ascii",
+  "ISO-8859-2",
+  "ISO-8859-3",
+  "ISO-8859-4",
+  "ISO-8859-5",
+  "ISO-8859-6",
+  "ISO-8859-6-I",
+  "ISO-8859-6-E",
+  "ISO-8859-7",
+  "ISO-8859-8",
+  "ISO-8859-8-I",
+  "ISO-8859-8-E",
+  "ISO-8859-9",
+  "ISO-8859-10",
+  "ISO-8859-13",
+  "ISO-8859-14",
+  "ISO-8859-15",
+  "ISO-8859-16",
+  "ISO-IR-111",
+  "windows-1250",
+  "windows-1251",
+  "windows-1253",
+  "windows-1254",
+  "windows-1255",
+  "windows-1256",
+  "windows-1257",
+  "windows-1258",
+  "TIS-620",
+  "windows-874",
+  "ISO-8859-11",
+  "KOI8-R",
+  "KOI8-U",
+  "x-mac-ce",
+  "x-mac-greek",
+  "x-mac-turkish",
+  "x-mac-croatian",
+  "x-mac-romanian",
+  "x-mac-cyrillic",
+  "x-mac-icelandic",
+  "armscii-8",
+  "x-viet-tcvn5712",
+  "VISCII",
+  "x-viet-vps",
+  "UTF-7",
+  "x-imap4-modified-utf7",
+  "UTF-16",
+  "UTF-16BE",
+  "UTF-16LE",
+  "T.61-8bit",
+  "x-user-defined",
+  "x-mac-arabic",
+  "x-mac-devanagari",
+  "x-mac-farsi",
+  "x-mac-gurmukhi",
+  "x-mac-gujarati",
+  "x-mac-hebrew",
+
+  "Adobe-Symbol-Encoding",
+  "x-zapf-dingbats",
+  "x-tscii",
+  "x-tamilttf-0",
+
+  "IBM850",
+  "IBM852",
+  "IBM855",
+  "IBM857",
+  "IBM862",
+  "IBM864",
+  "IBM864i",
+  "IBM866",
+  "Shift_JIS",
+  "ISO-2022-JP",
+  "EUC-JP",
+  "jis_0201",
+  "x-euc-tw",
+  "Big5",
+  "Big5-HKSCS",
+  "hkscs-1",
+  "EUC-KR",
+  "x-johab",
+  "x-windows-949",
+  "GB2312",
+  "gbk",
+  "HZ-GB-2312",
+  "gb18030",
+];
+
+var decoderList = [
+  "ISO-8859-1",
+  "windows-1252",
+  "x-mac-roman",
+  "UTF-8",
+  "us-ascii",
+  "ISO-8859-2",
+  "ISO-8859-3",
+  "ISO-8859-4",
+  "ISO-8859-5",
+  "ISO-8859-6",
+  "ISO-8859-6-I",
+  "ISO-8859-6-E",
+  "ISO-8859-7",
+  "ISO-8859-8",
+  "ISO-8859-8-I",
+  "ISO-8859-8-E",
+  "ISO-8859-9",
+  "ISO-8859-10",
+  "ISO-8859-13",
+  "ISO-8859-14",
+  "ISO-8859-15",
+  "ISO-8859-16",
+  "ISO-IR-111",
+  "windows-1250",
+  "windows-1251",
+  "windows-1253",
+  "windows-1254",
+  "windows-1255",
+  "windows-1256",
+  "windows-1257",
+  "windows-1258",
+  "TIS-620",
+  "windows-874",
+  "ISO-8859-11",
+  "KOI8-R",
+  "KOI8-U",
+  "x-mac-ce",
+  "x-mac-greek",
+  "x-mac-turkish",
+  "x-mac-croatian",
+  "x-mac-romanian",
+  "x-mac-cyrillic",
+  "x-mac-icelandic",
+  "armscii-8",
+  "x-viet-tcvn5712",
+  "VISCII",
+  "x-viet-vps",
+  "UTF-7",
+  "x-imap4-modified-utf7",
+  "UTF-16",
+  "UTF-16BE",
+  "UTF-16LE",
+  "T.61-8bit",
+  "x-user-defined",
+  "x-mac-arabic",
+  "x-mac-devanagari",
+  "x-mac-farsi",
+  "x-mac-gurmukhi",
+  "x-mac-gujarati",
+  "x-mac-hebrew",
+  "IBM850",
+  "IBM852",
+  "IBM855",
+  "IBM857",
+  "IBM862",
+  "IBM864",
+  "IBM864i",
+  "IBM866",
+  "Shift_JIS",
+  "ISO-2022-JP",
+  "EUC-JP",
+  "x-euc-tw",
+  "Big5",
+  "Big5-HKSCS",
+  "EUC-KR",
+  "x-johab",
+  "x-windows-949",
+  "GB2312",
+  "gbk",
+  "HZ-GB-2312",
+  "gb18030",
+  "ISO-2022-KR",
+  "ISO-2022-CN",
+];
+
+function verifyList(aEnumerator, aList)
+{
+  var count = 0;
+
+  while (aEnumerator.hasMore()) {
+    var result = aEnumerator.getNext();
+    for (var i = 0; i < aList.length; i++) {
+      if (result == aList[i]) {
+        count++;
+        break;
+      }
+    }
+    if (i == aList.length) {
+      do_throw("Unknown chardet: " + result);
+    }
+  }
+  do_check_eq(count, aList.length);
+}
+
+function run_test()
+{
+  var cm = Components.classes["@mozilla.org/charset-converter-manager;1"]
+           .getService(Components.interfaces.nsICharsetConverterManager);
+
+  verifyList(cm.GetCharsetDetectorList(), detectList);
+  verifyList(cm.getEncoderList(), encoderList);
+  verifyList(cm.getDecoderList(), decoderList);
+}
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -24,16 +24,17 @@ tail =
 [test_bug457886.js]
 [test_bug522931.js]
 [test_bug563283.js]
 [test_bug563618.js]
 [test_bug601429.js]
 [test_bug699673.js]
 [test_bug90411.js]
 [test_bug713519.js]
+[test_bug718500.js]
 [test_charset_conversion.js]
 [test_decode_8859-1.js]
 [test_decode_8859-10.js]
 [test_decode_8859-11.js]
 [test_decode_8859-13.js]
 [test_decode_8859-14.js]
 [test_decode_8859-15.js]
 [test_decode_8859-2.js]
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -62,17 +62,17 @@
 #endif
 
 #if !defined(OS_POSIX)
 // This condition must be kept in sync with the one in
 // ipc_message_utils.h, but this dummy definition of
 // base::FileDescriptor acts as a static assert that we only get one
 // def or the other (or neither, in which case code using
 // FileDescriptor fails to build)
-namespace base { class FileDescriptor { }; }
+namespace base { struct FileDescriptor { }; }
 #endif
 
 using mozilla::layers::LayerManager;
 
 namespace mozilla {
 
 typedef gfxPattern::GraphicsFilter GraphicsFilterType;
 typedef gfxASurface::gfxSurfaceType gfxSurfaceType;
--- a/js/src/jit-test/tests/basic/bug592927.js
+++ b/js/src/jit-test/tests/basic/bug592927.js
@@ -8,20 +8,20 @@ function g(x) {
     assertEq(x.arguments[1], "hello");
     x.arguments[1] = "bye";
     assertEq(x.arguments[1], "hello");
 }
 
 function f2(x, y) {
     arguments;
     x(f2);
-    assertEq(y, "bye");
+    assertEq(y, "hello");
 }
 
 function g2(x) {
     assertEq(x.arguments[1], "hello");
     x.arguments[1] = "bye";
-    assertEq(x.arguments[1], "bye");
+    assertEq(x.arguments[1], "hello");
 }
 
 f(g, "hello");
 f2(g2, "hello");
 
--- a/js/src/jit-test/tests/jaeger/argumentsOptimize-1.js
+++ b/js/src/jit-test/tests/jaeger/argumentsOptimize-1.js
@@ -3,12 +3,12 @@ function bar() {
   foo.arguments.length = 10;
 }
 
 function foo(x) {
   var a = arguments;
   var n = 0;
   bar();
   assertEq(x, 5);
-  assertEq(a.length, 10);
+  assertEq(a.length, 1);
 }
 
 foo(5);
--- a/js/src/jit-test/tests/jaeger/loops/hoist-05.js
+++ b/js/src/jit-test/tests/jaeger/loops/hoist-05.js
@@ -11,9 +11,9 @@ function foo(x, j, n) {
     bar(x, i);
     if (typeof q == 'undefined')
       a++;
   }
   return a;
 }
 
 var a = foo([1,2,3,4], 3, 100);
-assertEq(a, 49);
+assertEq(a, 0);
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -1528,17 +1528,17 @@ ScriptAnalysis::insertPhi(JSContext *cx,
 
     /*
      * Filter dupes inserted into small nodes to keep things clean and avoid
      * extra type constraints, but don't bother on large phi nodes to avoid
      * quadratic behavior.
      */
     if (node->length <= 8) {
         for (unsigned i = 0; i < node->length; i++) {
-            if (v.equals(node->options[i]))
+            if (v == node->options[i])
                 return;
         }
     }
 
     if (trackUseChain(v)) {
         SSAUseChain *&uses = useChain(v);
 
         SSAUseChain *use = cx->typeLifoAlloc().new_<SSAUseChain>();
@@ -1572,17 +1572,17 @@ ScriptAnalysis::insertPhi(JSContext *cx,
 }
 
 inline void
 ScriptAnalysis::mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv)
 {
     /* Make sure that v is accounted for in the pending value or phi value at pv. */
     JS_ASSERT(v.kind() != SSAValue::EMPTY && pv->value.kind() != SSAValue::EMPTY);
 
-    if (v.equals(pv->value))
+    if (v == pv->value)
         return;
 
     if (pv->value.kind() != SSAValue::PHI || pv->value.phiOffset() < offset) {
         SSAValue ov = pv->value;
         if (makePhi(cx, pv->slot, offset, &pv->value)) {
             insertPhi(cx, pv->value, v);
             insertPhi(cx, pv->value, ov);
         }
@@ -1702,17 +1702,17 @@ ScriptAnalysis::mergeExceptionTarget(JSC
      * try block starts and overwritten before it is finished can still be
      * seen at exception handlers via exception paths.
      */
     for (unsigned i = 0; i < exceptionTargets.length(); i++) {
         Vector<SlotValue> *pending = getCode(exceptionTargets[i]).pendingValues;
 
         bool duplicate = false;
         for (unsigned i = 0; i < pending->length(); i++) {
-            if ((*pending)[i].slot == slot && (*pending)[i].value.equals(value))
+            if ((*pending)[i].slot == slot && (*pending)[i].value == value)
                 duplicate = true;
         }
 
         if (!duplicate && !pending->append(SlotValue(slot, value)))
             setOOM(cx);
     }
 }
 
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -585,17 +585,17 @@ class SSAValue
 
     Kind kind() const {
         JS_ASSERT(u.pushed.kind == u.var.kind && u.pushed.kind == u.phi.kind);
 
         /* Use a bitmask because MSVC wants to use -1 for PHI nodes. */
         return (Kind) (u.pushed.kind & 0x3);
     }
 
-    bool equals(const SSAValue &o) const {
+    bool operator==(const SSAValue &o) const {
         return !memcmp(this, &o, sizeof(SSAValue));
     }
 
     /* Accessors for values pushed by a bytecode within this script. */
 
     uint32_t pushedOffset() const {
         JS_ASSERT(kind() == PUSHED);
         return u.pushed.offset;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1673,23 +1673,17 @@ IsJITBrokenHere()
     return isBroken;
 }
 #endif
 
 void
 JSContext::updateJITEnabled()
 {
 #ifdef JS_METHODJIT
-    methodJitEnabled = (runOptions & JSOPTION_METHODJIT) &&
-                       !IsJITBrokenHere()
-# if defined JS_CPU_X86 || defined JS_CPU_X64
-                       && JSC::MacroAssemblerX86Common::getSSEState() >=
-                          JSC::MacroAssemblerX86Common::HasSSE2
-# endif
-                        ;
+    methodJitEnabled = (runOptions & JSOPTION_METHODJIT) && !IsJITBrokenHere();
 #endif
 }
 
 size_t
 JSContext::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
 {
     /*
      * There are other JSContext members that could be measured; the following
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -118,17 +118,17 @@ js_GetArgsValue(JSContext *cx, StackFram
     argsobj = js_GetArgsObject(cx, fp);
     if (!argsobj)
         return JS_FALSE;
     vp->setObject(*argsobj);
     return JS_TRUE;
 }
 
 js::ArgumentsObject *
-ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp)
+ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
     JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
     if (!proto)
         return NULL;
 
     RootedVarTypeObject type(cx);
@@ -161,17 +161,17 @@ ArgumentsObject::create(JSContext *cx, u
     if (!obj)
         return NULL;
 
     ArgumentsObject &argsobj = obj->asArguments();
 
     JS_ASSERT(UINT32_MAX > (uint64_t(argc) << PACKED_BITS_COUNT));
     argsobj.initInitialLength(argc);
     argsobj.initData(data);
-    argsobj.setStackFrame(strict ? NULL : fp);
+    argsobj.setStackFrame(NULL);
 
     JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
     JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
 
     return &argsobj;
 }
 
 struct STATIC_SKIP_INFERENCE PutArg
@@ -206,18 +206,17 @@ js_GetArgsObject(JSContext *cx, StackFra
     if (!fp->script()->createdArgs)
         types::MarkArgumentsCreated(cx, fp->script());
 
     /* Create an arguments object for fp only if it lacks one. */
     JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
     if (fp->hasArgsObj())
         return &fp->argsObj();
 
-    ArgumentsObject *argsobj =
-        ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee(), fp);
+    ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
     if (!argsobj)
         return argsobj;
 
     /*
      * Strict mode functions have arguments objects that copy the initial
      * actual parameter values.  It is the caller's responsibility to get the
      * arguments object before any parameters are modified!  (The emitter
      * ensures this by synthesizing an arguments access at the start of any
@@ -1107,17 +1106,29 @@ fun_getProperty(JSContext *cx, JSObject 
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) {
         /* Warn if strict about f.arguments or equivalent unqualified uses. */
         if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage,
                                           NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) {
             return false;
         }
 
-        return js_GetArgsValue(cx, fp, vp);
+        /*
+         * Purposefully disconnect the returned arguments object from the frame
+         * by always creating a new copy that does not alias formal parameters.
+         * This allows function-local analysis to determine that formals are
+         * not aliased and generally simplifies arguments objects.
+         */
+        ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
+        if (!argsobj)
+            return false;
+
+        fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
+        *vp = ObjectValue(*argsobj);
+        return true;
     }
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
         if (!fp->prev())
             return true;
 
         StackFrame *frame = js_GetScriptedCaller(cx, fp->prev());
         if (frame && !frame->getValidCalleeObject(cx, vp))
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -54,16 +54,19 @@
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jsiter.h"
 
 #include "frontend/TokenStream.h"
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
+#ifdef JS_METHODJIT
+# include "assembler/assembler/MacroAssembler.h"
+#endif
 
 #include "jsatominlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 #include "vm/Stack-inl.h"
 
@@ -1956,18 +1959,23 @@ TypeSet::needsBarrier(JSContext *cx)
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 void
 TypeCompartment::init(JSContext *cx)
 {
     PodZero(this);
 
-    if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE)
-        inferenceEnabled = true;
+    if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE) {
+#ifdef JS_METHODJIT
+        JSC::MacroAssembler masm;
+        if (masm.supportsFloatingPoint())
+#endif
+            inferenceEnabled = true;
+    }
 }
 
 TypeObject *
 TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
                                JSProtoKey key, JSObject *proto, bool unknown)
 {
     RootObject root(cx, &proto);
 
@@ -4296,17 +4304,17 @@ ScriptAnalysis::followEscapingArguments(
     /*
      * trackUseChain is false for initial values of variables, which
      * cannot hold the script's arguments object.
      */
     if (!trackUseChain(v))
         return true;
 
     for (unsigned i = 0; i < seen->length(); i++) {
-        if (v.equals((*seen)[i]))
+        if (v == (*seen)[i])
             return true;
     }
     if (!seen->append(v)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
     SSAUseChain *use = useChain(v);
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -826,17 +826,17 @@ static const JSC::MacroAssembler::Regist
         if (key.isConstant())
             key.index_ += delta;
         else
             add32(Imm32(delta), key.reg());
     }
 
     void loadFrameActuals(JSFunction *fun, RegisterID reg) {
         /* Bias for the case where there was an arguments overflow. */
-        load32(Address(JSFrameReg, StackFrame::offsetOfArgs()), reg);
+        load32(Address(JSFrameReg, StackFrame::offsetOfNumActual()), reg);
         add32(Imm32(fun->nargs + 2), reg);
         Jump overflowArgs = branchTest32(Assembler::NonZero,
                                          Address(JSFrameReg, StackFrame::offsetOfFlags()),
                                          Imm32(StackFrame::OVERFLOW_ARGS));
         move(Imm32(fun->nargs), reg);
         overflowArgs.linkTo(label(), this);
         lshiftPtr(Imm32(3), reg);
         negPtr(reg);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -809,27 +809,27 @@ mjit::Compiler::generatePrologue()
                 stubcc.linkExitDirect(mismatch, stubcc.masm.label());
                 OOL_STUBCALL(stubs::FunctionFramePrologue, REJOIN_FUNCTION_PROLOGUE);
                 stubcc.crossJump(stubcc.masm.jump(), masm.label());
             }
         }
 
         if (outerScript->usesArguments && !script->function()->isHeavyweight()) {
             /*
-             * Make sure that fp->args.nactual is always coherent. This may be
+             * Make sure that fp->u.nactual is always coherent. This may be
              * inspected directly by JIT code, and is not guaranteed to be
              * correct if the UNDERFLOW and OVERFLOW flags are not set.
              */
             Jump hasArgs = masm.branchTest32(Assembler::NonZero, FrameFlagsAddress(),
                                              Imm32(StackFrame::OVERRIDE_ARGS |
                                                    StackFrame::UNDERFLOW_ARGS |
                                                    StackFrame::OVERFLOW_ARGS |
                                                    StackFrame::HAS_ARGS_OBJ));
             masm.storePtr(ImmPtr((void *)(size_t) script->function()->nargs),
-                          Address(JSFrameReg, StackFrame::offsetOfArgs()));
+                          Address(JSFrameReg, StackFrame::offsetOfNumActual()));
             hasArgs.linkTo(masm.label(), &masm);
         }
 
         j.linkTo(masm.label(), &masm);
     }
 
     if (cx->typeInferenceEnabled()) {
 #ifdef DEBUG
@@ -4522,22 +4522,21 @@ mjit::Compiler::jsop_getprop(PropertyNam
                 bumpPropCounter(PC, OpcodeCounts::PROP_DEFINITE);
             if (!isObject)
                 stubcc.rejoin(Changes(1));
             return true;
         }
 
         /*
          * Check if we are accessing the 'length' of the lazy arguments for the
-         * current frame. No actual arguments object has ever been constructed
-         * for the script, so we can go straight to nactual.
+         * current frame.
          */
         if (types->isLazyArguments(cx)) {
             frame.pop();
-            frame.pushWord(Address(JSFrameReg, StackFrame::offsetOfArgs()), JSVAL_TYPE_INT32);
+            frame.pushWord(Address(JSFrameReg, StackFrame::offsetOfNumActual()), JSVAL_TYPE_INT32);
             if (script->pcCounters)
                 bumpPropCounter(PC, OpcodeCounts::PROP_DEFINITE);
             return true;
         }
     }
 
     /* If the access will definitely be fetching a particular value, nop it. */
     bool testObject;
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -633,16 +633,17 @@ private:
     bool jsop_xname(PropertyName *name);
     void enterBlock(JSObject *obj);
     void leaveBlock();
     void emitEval(uint32_t argc);
     void jsop_arguments(RejoinState rejoin);
     bool jsop_tableswitch(jsbytecode *pc);
 
     /* Fast arithmetic. */
+    bool jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type, FrameEntry *lhs, FrameEntry *rhs);
     bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
     void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                           JSValueType type, bool cannotOverflow, bool ignoreOverflow);
     void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub,
                                  JSValueType type);
     void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                             JSValueType type);
     void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -171,16 +171,31 @@ mjit::Compiler::maybeJumpIfNotDouble(Ass
         else
             mj.setJump(masm.testDouble(Assembler::NotEqual, frame.addressOf(fe)));
     } else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) {
         mj.setJump(masm.jump());
     }
 }
 
 bool
+mjit::Compiler::jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type,
+                                 FrameEntry *lhs, FrameEntry *rhs)
+{
+    bool isStringResult = (op == JSOP_ADD) &&
+                          (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING));
+    JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
+
+    prepareStubCall(Uses(2));
+    INLINE_STUBCALL(stub, REJOIN_BINARY);
+    frame.popn(2);
+    frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
+    return true;
+}
+
+bool
 mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
         if (!v.isInt32() && typeSet && !typeSet->hasType(types::Type::DoubleType())) {
@@ -200,26 +215,17 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
     /*
      * Bail out if there are unhandled types or ops.
      * This is temporary while ops are still being implemented.
      */
     if ((lhs->isConstant() && rhs->isConstant()) ||
         (lhs->isTypeKnown() && (lhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)) ||
         (rhs->isTypeKnown() && (rhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)))
     {
-        bool isStringResult = (op == JSOP_ADD) &&
-                              (lhs->isType(JSVAL_TYPE_STRING) ||
-                               rhs->isType(JSVAL_TYPE_STRING));
-        JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
-
-        prepareStubCall(Uses(2));
-        INLINE_STUBCALL(stub, REJOIN_BINARY);
-        frame.popn(2);
-        frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
-        return true;
+        return jsop_binary_slow(op, stub, type, lhs, rhs);
     }
 
     /*
      * If this is an operation on which integer overflows can be ignored, treat
      * the result as an integer even if it has been marked as overflowing by
      * the interpreter. Doing this changes the values we maintain on the stack
      * from those the interpreter would maintain; this is OK as values derived
      * from ignored overflows are not live across points where the interpreter
@@ -233,16 +239,19 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
         op == JSOP_ADD && ignoreOverflow) {
         type = JSVAL_TYPE_INT32;
     }
 
     /* Can do int math iff there is no double constant and the op is not division. */
     bool canDoIntMath = op != JSOP_DIV && type != JSVAL_TYPE_DOUBLE &&
                         !(rhs->isType(JSVAL_TYPE_DOUBLE) || lhs->isType(JSVAL_TYPE_DOUBLE));
 
+    if (!masm.supportsFloatingPoint() && (!canDoIntMath || frame.haveSameBacking(lhs, rhs)))
+        return jsop_binary_slow(op, stub, type, lhs, rhs);
+
     if (canDoIntMath)
         jsop_binary_full(lhs, rhs, op, stub, type, cannotOverflow, ignoreOverflow);
     else
         jsop_binary_double(lhs, rhs, op, stub, type);
 
     return true;
 }
 
@@ -567,17 +576,17 @@ mjit::Compiler::jsop_binary_full(FrameEn
         emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
 
     MaybeJump rhsNotNumber2;
     if (!rhs->isTypeKnown())
         emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
 
     /* Perform the double addition. */
     MaybeJump doublePathDone;
-    if (!rhs->isTypeKnown() || lhsUnknownDone.isSet()) {
+    if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown())) {
         /* If the LHS type was not known, link its path here. */
         if (lhsUnknownDone.isSet())
             lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
         
         /* Perform the double operation. */
         EmitDoubleOp(op, regs.rhsFP, regs.lhsFP, stubcc.masm);
 
         /* Force the double back to memory. */
@@ -785,29 +794,32 @@ mjit::Compiler::jsop_binary_full(FrameEn
 }
 
 void
 mjit::Compiler::jsop_neg()
 {
     FrameEntry *fe = frame.peek(-1);
     JSValueType type = knownPushedType(0);
 
-    if (fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) {
+    if ((fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) ||
+        !masm.supportsFloatingPoint())
+    {
         prepareStubCall(Uses(1));
         INLINE_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
         frame.pop();
         frame.pushSynced(type);
         return;
     }
 
     JS_ASSERT(!fe->isConstant());
 
     /* Handle negation of a known double, or of a known integer which has previously overflowed. */
     if (fe->isType(JSVAL_TYPE_DOUBLE) ||
-        (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE)) {
+        (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE))
+    {
         FPRegisterID fpreg;
         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
             fpreg = frame.tempFPRegForData(fe);
         } else {
             fpreg = frame.allocFPReg();
             frame.convertInt32ToDouble(masm, fe, fpreg);
         }
 
@@ -1304,16 +1316,21 @@ void
 mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
                                    MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
                                    MaybeJump &lhsUnknownDone)
 {
     /* If the LHS is not a 32-bit integer, take OOL path. */
     Jump lhsNotInt32 = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg());
     stubcc.linkExitDirect(lhsNotInt32, stubcc.masm.label());
 
+    if (!masm.supportsFloatingPoint()) {
+        lhsNotDouble = stubcc.masm.jump();
+        return;
+    }
+
     /* OOL path for LHS as a double - first test LHS is double. */
     lhsNotDouble = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg());
 
     /* Ensure the RHS is a number. */
     MaybeJump rhsIsDouble;
     if (!rhs->isTypeKnown()) {
         rhsIsDouble = stubcc.masm.testDouble(Assembler::Equal, regs.rhsType.reg());
         rhsNotNumber = stubcc.masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
@@ -1349,16 +1366,21 @@ mjit::Compiler::emitLeftDoublePath(Frame
 void
 mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
                                     MaybeJump &rhsNotNumber2)
 {
     /* If the RHS is not a double, take OOL path. */
     Jump notInt32 = masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
     stubcc.linkExitDirect(notInt32, stubcc.masm.label());
 
+    if (!masm.supportsFloatingPoint()) {
+        rhsNotNumber2 = stubcc.masm.jump();
+        return;
+    }
+
     /* Now test if RHS is a double. */
     rhsNotNumber2 = stubcc.masm.testDouble(Assembler::NotEqual, regs.rhsType.reg());
 
     /* We know LHS is an integer. */
     if (lhs->isConstant())
         slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
     else
         stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
@@ -1566,17 +1588,17 @@ mjit::Compiler::jsop_relational_full(JSO
         emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
 
     MaybeJump rhsNotNumber2;
     if (!rhs->isTypeKnown())
         emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
 
     /* Both double paths will join here. */
     bool hasDoublePath = false;
-    if (!rhs->isTypeKnown() || lhsUnknownDone.isSet())
+    if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown()))
         hasDoublePath = true;
 
     /* Integer path - figure out the immutable side. */
     JSOp cmpOp = op;
     int32_t value = 0;
     RegisterID cmpReg;
     MaybeRegisterID reg;
     if (regs.lhsData.isSet()) {
@@ -1607,35 +1629,35 @@ mjit::Compiler::jsop_relational_full(JSO
         MaybeJump doubleTest, doubleFall;
         Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
         if (hasDoublePath) {
             if (lhsUnknownDone.isSet())
                 lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
             frame.sync(stubcc.masm, Uses(frame.frameSlots()));
             doubleTest = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
             doubleFall = stubcc.masm.jump();
-
-            /* Link all incoming slow paths to here. */
-            if (lhsNotDouble.isSet()) {
-                lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-                if (rhsNotNumber.isSet())
-                    rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-            }
-            if (rhsNotNumber2.isSet())
-                rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+        }
 
-            /*
-             * For fusions, spill the tracker state. xmm* remain intact. Note
-             * that frame.sync() must be used directly, to avoid syncExit()'s
-             * jumping logic.
-             */
-            frame.sync(stubcc.masm, Uses(frame.frameSlots()));
-            stubcc.leave();
-            OOL_STUBCALL(stub, REJOIN_BRANCH);
+        /* Link all incoming slow paths to here. */
+        if (lhsNotDouble.isSet()) {
+            lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+            if (rhsNotNumber.isSet())
+                rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
         }
+        if (rhsNotNumber2.isSet())
+            rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+
+        /*
+         * For fusions, spill the tracker state. xmm* remain intact. Note
+         * that frame.sync() must be used directly, to avoid syncExit()'s
+         * jumping logic.
+         */
+        frame.sync(stubcc.masm, Uses(frame.frameSlots()));
+        stubcc.leave();
+        OOL_STUBCALL(stub, REJOIN_BRANCH);
 
         /* Forget the world, preserving data. */
         frame.pinReg(cmpReg);
         if (reg.isSet())
             frame.pinReg(reg.reg());
         
         frame.popn(2);
 
@@ -1696,31 +1718,31 @@ mjit::Compiler::jsop_relational_full(JSO
             /* :FIXME: Use SET if we can? */
             Jump test = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
             stubcc.masm.move(Imm32(0), regs.result);
             Jump skip = stubcc.masm.jump();
             test.linkTo(stubcc.masm.label(), &stubcc.masm);
             stubcc.masm.move(Imm32(1), regs.result);
             skip.linkTo(stubcc.masm.label(), &stubcc.masm);
             doubleDone = stubcc.masm.jump();
+        }
 
-            /* Link all incoming slow paths to here. */
-            if (lhsNotDouble.isSet()) {
-                lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-                if (rhsNotNumber.isSet())
-                    rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
-            }
-            if (rhsNotNumber2.isSet())
-                rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+        /* Link all incoming slow paths to here. */
+        if (lhsNotDouble.isSet()) {
+            lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+            if (rhsNotNumber.isSet())
+                rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
+        }
+        if (rhsNotNumber2.isSet())
+            rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 
-            /* Emit the slow path - note full frame syncage. */
-            frame.sync(stubcc.masm, Uses(2));
-            stubcc.leave();
-            OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
-        }
+        /* Emit the slow path - note full frame syncage. */
+        frame.sync(stubcc.masm, Uses(2));
+        stubcc.leave();
+        OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
         /* Get an integer comparison condition. */
         Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);
 
         /* Emit the compare & set. */
         if (reg.isSet())
             masm.branchValue(i32Cond, cmpReg, reg.reg(), regs.result);
         else
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -96,38 +96,52 @@ mjit::Compiler::ensureInteger(FrameEntry
         stubcc.masm.addDouble(fpreg, fptemp);
         stubcc.masm.branchConvertDoubleToInt32(fptemp, data, isDouble, Registers::FPConversionTemp);
         stubcc.crossJump(stubcc.masm.jump(), masm.label());
         isDouble.linkTo(syncPath, &stubcc.masm);
 
         frame.freeReg(fptemp);
         frame.learnType(fe, JSVAL_TYPE_INT32, data);
     } else if (!fe->isType(JSVAL_TYPE_INT32)) {
-        FPRegisterID fptemp = frame.allocFPReg();
-        RegisterID typeReg = frame.tempRegForType(fe);
-        frame.pinReg(typeReg);
-        RegisterID dataReg = frame.copyDataIntoReg(fe);
-        frame.unpinReg(typeReg);
-
-        Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
-
-        Label syncPath = stubcc.syncExitAndJump(uses);
-        stubcc.linkExitDirect(intGuard, stubcc.masm.label());
-
-        /* Try an OOL path to truncate doubles representing int32s. */
-        Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
-        doubleGuard.linkTo(syncPath, &stubcc.masm);
-
-        frame.loadDouble(fe, fptemp, stubcc.masm);
-        Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
-        truncateGuard.linkTo(syncPath, &stubcc.masm);
-        stubcc.crossJump(stubcc.masm.jump(), masm.label());
-
-        frame.freeReg(fptemp);
-        frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+        if (masm.supportsFloatingPoint()) {
+            FPRegisterID fptemp = frame.allocFPReg();
+            RegisterID typeReg = frame.tempRegForType(fe);
+            frame.pinReg(typeReg);
+            RegisterID dataReg = frame.copyDataIntoReg(fe);
+            frame.unpinReg(typeReg);
+
+            Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
+
+            Label syncPath = stubcc.syncExitAndJump(uses);
+            stubcc.linkExitDirect(intGuard, stubcc.masm.label());
+
+            /* Try an OOL path to truncate doubles representing int32s. */
+            Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
+            doubleGuard.linkTo(syncPath, &stubcc.masm);
+
+            frame.loadDouble(fe, fptemp, stubcc.masm);
+            Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
+            truncateGuard.linkTo(syncPath, &stubcc.masm);
+            stubcc.crossJump(stubcc.masm.jump(), masm.label());
+
+            frame.freeReg(fptemp);
+            frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+        } else {
+            RegisterID typeReg = frame.tempRegForType(fe);
+            frame.pinReg(typeReg);
+            RegisterID dataReg = frame.copyDataIntoReg(fe);
+            frame.unpinReg(typeReg);
+
+            Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
+
+            Label syncPath = stubcc.syncExitAndJump(uses);
+            stubcc.linkExitDirect(intGuard, syncPath);
+
+            frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
+        }
     }
 }
 
 void
 mjit::Compiler::jsop_bitnot()
 {
     FrameEntry *top = frame.peek(-1);
 
@@ -557,16 +571,18 @@ mjit::Compiler::jsop_relational(JSOp op,
         }
     }
 
     if (frame.haveSameBacking(lhs, rhs)) {
         return emitStubCmpOp(stub, target, fused);
     } else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
         return emitStubCmpOp(stub, target, fused);
     } else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) {
+        if (!masm.supportsFloatingPoint())
+            return emitStubCmpOp(stub, target, fused);
         return jsop_relational_double(op, stub, target, fused);
     } else if (cx->typeInferenceEnabled() &&
                lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) {
         return jsop_relational_int(op, target, fused);
     } else {
         return jsop_relational_full(op, stub, target, fused);
     }
 }
@@ -1900,17 +1916,17 @@ mjit::Compiler::jsop_getelem_args()
     if (!key.isConstant())
         frame.pinReg(key.reg());
 
     RegisterID dataReg = frame.allocReg();
     RegisterID typeReg = frame.allocReg();
 
     // Guard on nactual.
     if (!hoistedLength) {
-        Address nactualAddr(JSFrameReg, StackFrame::offsetOfArgs());
+        Address nactualAddr(JSFrameReg, StackFrame::offsetOfNumActual());
         MaybeJump rangeGuard;
         if (key.isConstant()) {
             JS_ASSERT(key.index() >= 0);
             rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, Imm32(key.index()));
         } else {
             rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, key.reg());
         }
         stubcc.linkExit(rangeGuard.get(), Uses(2));
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -1525,20 +1525,22 @@ FrameState::merge(Assembler &masm, Chang
      */
 
     /*
      * For any changed values we are merging back which we consider to be doubles,
      * ensure they actually are doubles.  They must be doubles or ints, but we
      * do not require stub paths to always generate a double when needed.
      * :FIXME: we check this on OOL stub calls, but not inline stub calls.
      */
-    for (unsigned i = 0; i < changes.nchanges; i++) {
-        FrameEntry *fe = a->sp - 1 - i;
-        if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
-            masm.ensureInMemoryDouble(addressOf(fe));
+    if (cx->typeInferenceEnabled()) {
+        for (unsigned i = 0; i < changes.nchanges; i++) {
+            FrameEntry *fe = a->sp - 1 - i;
+            if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
+                masm.ensureInMemoryDouble(addressOf(fe));
+        }
     }
 
     uint32_t mask = Registers::AvailAnyRegs & ~freeRegs.freeMask;
     Registers search(mask);
 
     while (!search.empty(mask)) {
         AnyRegisterID reg = search.peekReg(mask);
         FrameEntry *fe = regstate(reg).usedBy();
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -1431,17 +1431,17 @@ LoopState::restoreInvariants(jsbytecode 
             Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary));
             masm.loadFrameActuals(outerScript->function(), T0);
             masm.storePayload(T0, address);
             break;
           }
 
           case InvariantEntry::INVARIANT_ARGS_LENGTH: {
             Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary));
-            masm.load32(Address(JSFrameReg, StackFrame::offsetOfArgs()), T0);
+            masm.load32(Address(JSFrameReg, StackFrame::offsetOfNumActual()), T0);
             masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), T0, address);
             break;
           }
 
           case InvariantEntry::INVARIANT_PROPERTY: {
             uint32_t object = entry.u.property.objectSlot;
             Jump notObject = masm.testObject(Assembler::NotEqual, frame.addressOf(object));
             jumps->append(notObject);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2434,17 +2434,17 @@ GetElementIC::attachArguments(VMFrame &f
         masm.loadValueAsComponents(frameEntry, typeReg, objReg);
     }    
     Jump done2 = masm.jump();
 
     notFormalArg.linkTo(masm.label(), &masm);
 
     masm.push(typeReg);
 
-    Address argsObject(typeReg, StackFrame::offsetOfArgs());
+    Address argsObject(typeReg, StackFrame::offsetOfArgsObj());
     masm.loadPtr(argsObject, typeReg);
 
     masm.load32(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), 
                 typeReg); 
     masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), typeReg); 
 
     /* This basically does fp - (numFormalArgs + numActualArgs + 2) */
 
@@ -2532,16 +2532,24 @@ GetElementIC::attachTypedArray(VMFrame &
     // Load the array's packed data vector.
     masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
 
     Int32Key key = idRemat.isConstant()
                  ? Int32Key::FromConstant(v.toInt32())
                  : Int32Key::FromRegister(idRemat.dataReg());
 
     JSObject *tarray = js::TypedArray::getTypedArray(obj);
+    if (!masm.supportsFloatingPoint() &&
+        (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
+         TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64 ||
+         TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT32))
+    {
+        return disable(cx, "fpu not supported");
+    }
+
     MaybeRegisterID tempReg;
     masm.loadFromTypedArray(TypedArray::getType(tarray), objReg, key, typeReg, objReg, tempReg);
 
     Jump done = masm.jump();
 
     updatePCCounters(cx, masm);
 
     PICLinker buffer(masm, *this);
@@ -2824,16 +2832,23 @@ SetElementIC::attachTypedArray(VMFrame &
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue));
     else
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
 
     // Load the array's packed data vector.
     masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
 
     JSObject *tarray = js::TypedArray::getTypedArray(obj);
+    if (!masm.supportsFloatingPoint() &&
+        (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
+         TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64))
+    {
+        return disable(cx, "fpu not supported");
+    }
+
     int shift = js::TypedArray::slotWidth(obj);
     if (hasConstantKey) {
         Address addr(objReg, keyValue * shift);
         if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
             return error(cx);
     } else {
         Assembler::Scale scale = Assembler::TimesOne;
         switch (shift) {
--- a/js/src/tests/js1_4/Functions/function-001.js
+++ b/js/src/tests/js1_4/Functions/function-001.js
@@ -92,17 +92,17 @@ new TestCase(
   SECTION,
   "return arguments when function contains an arguments property",
   "PASS",
   TestFunction_3( "P", "A", "S", "S" ) +"");
 
 new TestCase(
   SECTION,
   "return function.arguments when function contains an arguments property",
-  "PASS",
+  "[object Arguments]",
   TestFunction_4( "F", "A", "I", "L" ) +"");
 
 test();
 
 function TestFunction_1( a, b, c, d, e ) {
   return arguments;
 }
 
@@ -111,12 +111,12 @@ function TestFunction_2( a, b, c, d, e )
 }
 
 function TestFunction_3( a, b, c, d, e ) {
   var arguments = "PASS";
   return arguments;
 }
 
 function TestFunction_4( a, b, c, d, e ) {
-  var arguments = "PASS";
+  var arguments = "FAIL";
   return TestFunction_4.arguments;
 }
 
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -166,18 +166,17 @@ class ArgumentsObject : public JSObject
 #endif
 
     void initInitialLength(uint32_t length);
 
     void initData(ArgumentsData *data);
 
   public:
     /* Create an arguments object for the given callee function and frame. */
-    static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee,
-                                   StackFrame *fp);
+    static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee);
 
     /*
      * Return the initial length of the arguments.  This may differ from the
      * current value of arguments.length!
      */
     inline uint32_t initialLength() const;
 
     /* True iff arguments.length has been assigned or its attributes changed. */
@@ -216,34 +215,34 @@ class ArgumentsObject : public JSObject
     inline void setStackFrame(js::StackFrame *frame);
 };
 
 class NormalArgumentsObject : public ArgumentsObject
 {
     friend bool JSObject::isNormalArguments() const;
     friend struct EmptyShape; // for EmptyShape::getEmptyArgumentsShape
     friend ArgumentsObject *
-    ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp);
+    ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee);
 
   public:
     /*
      * Stores arguments.callee, or MagicValue(JS_ARGS_HOLE) if the callee has
      * been cleared.
      */
     inline const js::Value &callee() const;
 
     /* Clear the location storing arguments.callee's initial value. */
     inline void clearCallee();
 };
 
 class StrictArgumentsObject : public ArgumentsObject
 {
     friend bool JSObject::isStrictArguments() const;
     friend ArgumentsObject *
-    ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp);
+    ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee);
 };
 
 } // namespace js
 
 js::NormalArgumentsObject &
 JSObject::asNormalArguments()
 {
     JS_ASSERT(isNormalArguments());
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -152,17 +152,17 @@ StackFrame::initCallFrame(JSContext *cx,
                             LOWERED_CALL_APPLY |
                             OVERFLOW_ARGS |
                             UNDERFLOW_ARGS)) == 0);
     JS_ASSERT(script == callee.script());
 
     /* Initialize stack frame members. */
     flags_ = FUNCTION | HAS_PREVPC | HAS_SCOPECHAIN | HAS_BLOCKCHAIN | flagsArg;
     exec.fun = &callee;
-    args.nactual = nactual;
+    u.nactual = nactual;
     scopeChain_ = callee.environment();
     ncode_ = NULL;
     initPrev(cx);
     blockChain_= NULL;
     JS_ASSERT(!hasBlockChain());
     JS_ASSERT(!hasHookData());
     JS_ASSERT(annotation() == NULL);
     JS_ASSERT(!hasCallObj());
@@ -218,17 +218,17 @@ StackFrame::initJitFrameCallerHalf(Stack
 /*
  * The "early prologue" refers to either the fast path or arity check path up
  * to the "late prologue".
  */
 inline void
 StackFrame::initJitFrameEarlyPrologue(JSFunction *fun, uint32_t nactual)
 {
     exec.fun = fun;
-    args.nactual = nactual;
+    u.nactual = nactual;
 }
 
 /*
  * The "late prologue" (in generatePrologue) extends from the join point of the
  * fast path and arity check to where the call object is (possibly) created.
  */
 inline bool
 StackFrame::initJitFrameLatePrologue(JSContext *cx, Value **limit)
@@ -321,56 +321,54 @@ struct CopyTo
         return true;
     }
 };
 
 inline uintN
 StackFrame::numActualArgs() const
 {
     /*
-     * args.nactual is always coherent, except for method JIT frames where the
+     * u.nactual is always coherent, except for method JIT frames where the
      * callee does not access its arguments and the number of actual arguments
      * matches the number of formal arguments. The JIT requires that all frames
      * which do not have an arguments object and use their arguments have a
-     * coherent args.nactual (even though the below code may not use it), as
+     * coherent u.nactual (even though the below code may not use it), as
      * JIT code may access the field directly.
      */
     JS_ASSERT(hasArgs());
     if (JS_UNLIKELY(flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS)))
-        return hasArgsObj() ? argsObj().initialLength() : args.nactual;
+        return u.nactual;
     return numFormalArgs();
 }
 
 inline Value *
 StackFrame::actualArgs() const
 {
     JS_ASSERT(hasArgs());
     Value *argv = formalArgs();
-    if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS)) {
-        uintN nactual = hasArgsObj() ? argsObj().initialLength() : args.nactual;
-        return argv - (2 + nactual);
-    }
+    if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
+        return argv - (2 + u.nactual);
     return argv;
 }
 
 inline Value *
 StackFrame::actualArgsEnd() const
 {
     JS_ASSERT(hasArgs());
     if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
         return formalArgs() - 2;
     return formalArgs() + numActualArgs();
 }
 
 inline void
 StackFrame::setArgsObj(ArgumentsObject &obj)
 {
-    JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
+    JS_ASSERT_IF(hasArgsObj(), &obj == argsObj_);
     JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.initialLength());
-    args.obj = &obj;
+    argsObj_ = &obj;
     flags_ |= HAS_ARGS_OBJ;
 }
 
 inline void
 StackFrame::setScopeChainNoCallObj(JSObject &obj)
 {
 #ifdef DEBUG
     JS_ASSERT(&obj != NULL);
@@ -459,20 +457,18 @@ StackFrame::functionEpilogue()
     if (maintainNestingState())
         types::NestingEpilogue(this);
 }
 
 inline void
 StackFrame::updateEpilogueFlags()
 {
     if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
-        if (hasArgsObj() && !argsObj().maybeStackFrame()) {
-            args.nactual = args.obj->initialLength();
+        if (hasArgsObj() && !argsObj().maybeStackFrame())
             flags_ &= ~HAS_ARGS_OBJ;
-        }
         if (hasCallObj() && !callObj().maybeStackFrame()) {
             /*
              * For function frames, the call object may or may not have have an
              * enclosing DeclEnv object, so we use the callee's parent, since
              * it was the initial scope chain. For global (strict) eval frames,
              * there is no callee, but the call object's parent is the initial
              * scope chain.
              */
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -83,23 +83,23 @@ StackFrame::initExecuteFrame(JSScript *s
         flags_ |= (prev->flags_ & (FUNCTION | GLOBAL));
 
     Value *dstvp = (Value *)this - 2;
     dstvp[1] = thisv;
 
     if (isFunctionFrame()) {
         dstvp[0] = prev->calleev();
         exec = prev->exec;
-        args.script = script;
+        u.evalScript = script;
     } else {
         JS_ASSERT(isGlobalFrame());
         dstvp[0] = NullValue();
         exec.script = script;
 #ifdef DEBUG
-        args.script = (JSScript *)0xbad;
+        u.evalScript = (JSScript *)0xbad;
 #endif
     }
 
     scopeChain_ = &scopeChain;
     prev_ = prev;
     prevpc_ = regs ? regs->pc : (jsbytecode *)0xbad;
     prevInline_ = regs ? regs->inlined() : NULL;
     blockChain_ = NULL;
@@ -229,36 +229,17 @@ StackSegment::contains(const FrameRegs *
 bool
 StackSegment::contains(const CallArgsList *call) const
 {
     if (!call || !calls_)
         return false;
 
     /* NB: this depends on the continuity of segments in memory. */
     Value *vp = call->array();
-    bool ret = vp > slotsBegin() && vp <= calls_->array();
-
-    /*
-     * :XXX: Disabled. Including this check changes the asymptotic complexity
-     * of code which calls this function.
-     */
-#if 0
-#ifdef DEBUG
-    bool found = false;
-    for (CallArgsList *c = maybeCalls(); c->argv() > slotsBegin(); c = c->prev()) {
-        if (c == call) {
-            found = true;
-            break;
-        }
-    }
-    JS_ASSERT(found == ret);
-#endif
-#endif
-
-    return ret;
+    return vp > slotsBegin() && vp <= calls_->array();
 }
 
 StackFrame *
 StackSegment::computeNextFrame(const StackFrame *f) const
 {
     JS_ASSERT(contains(f) && f != fp());
 
     StackFrame *next = fp();
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -355,27 +355,27 @@ class StackFrame
 
   private:
     mutable uint32_t    flags_;         /* bits described by Flags */
     union {                             /* describes what code is executing in a */
         JSScript        *script;        /*   global frame */
         JSFunction      *fun;           /*   function frame, pre GetScopeChain */
     } exec;
     union {                             /* describes the arguments of a function */
-        uintN           nactual;        /*   before js_GetArgsObject */
-        ArgumentsObject *obj;           /*   after js_GetArgsObject */
-        JSScript        *script;        /* eval has no args, but needs a script */
-    } args;
+        uintN           nactual;        /*   for non-eval frames */
+        JSScript        *evalScript;    /*   the script of an eval-in-function */
+    } u;
     mutable JSObject    *scopeChain_;   /* current scope chain */
     StackFrame          *prev_;         /* previous cx->regs->fp */
     void                *ncode_;        /* return address for method JIT */
 
     /* Lazily initialized */
     Value               rval_;          /* return value of the frame */
     StaticBlockObject   *blockChain_;   /* innermost let block */
+    ArgumentsObject     *argsObj_;      /* if has HAS_ARGS_OBJ */
     jsbytecode          *prevpc_;       /* pc of previous frame*/
     JSInlinedSite       *prevInline_;   /* inlined site in previous frame */
     void                *hookData_;     /* closure returned by call hook */
     void                *annotation_;   /* perhaps remove with bug 546848 */
     JSRejoinState       rejoin_;        /* If rejoining into the interpreter
                                          * from JIT code, state at rejoin. */
 
     static void staticAsserts() {
@@ -573,23 +573,23 @@ class StackFrame
     JSInlinedSite *prevInline() {
         JS_ASSERT(flags_ & HAS_PREVPC);
         return prevInline_;
     }
 
     JSScript *script() const {
         JS_ASSERT(isScriptFrame());
         return isFunctionFrame()
-               ? isEvalFrame() ? args.script : fun()->script()
+               ? isEvalFrame() ? u.evalScript : fun()->script()