Merge m-i into m-c.
authorMounir Lamouri <mounir.lamouri@gmail.com>
Wed, 18 Jan 2012 11:28:32 +0100
changeset 84779 7538f4d4697c67c34ce17cb567a35133eb4cb1bc
parent 84699 f4049f65efc6e367c54643ad7c66b3e81e24bac5 (current diff)
parent 84778 715e4b7e3b51fded840bec05b9294cc9b8506feb (diff)
child 84786 f93675b9e0ac52a581a549e135c4c5631cdd761d
child 84793 2813a0ddc819fb89f977bb8d7636e74a10248001
push id21873
push usermlamouri@mozilla.com
push dateWed, 18 Jan 2012 10:29:07 +0000
treeherdermozilla-central@7538f4d4697c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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();
 }