Backout af0a7f54f483 (bug 704691), 17b4093b5ec5, 23f26ba05f1a (bug 697383) for various failures
authorMarco Bonardo <mbonardo@mozilla.com>
Mon, 28 Nov 2011 23:53:22 +0100
changeset 80918 af3ceb7d6902100b215620fa813d447d197f3f76
parent 80917 af0a7f54f4830fc493bb34197bff4c1641799369
child 80919 d984d11bffea9ce760e2427dd60f508857636af2
push id353
push usertim.taubert@gmx.de
push dateWed, 30 Nov 2011 05:45:09 +0000
treeherderfx-team@cc94a16983b0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs704691, 697383
milestone11.0a1
backs outaf0a7f54f4830fc493bb34197bff4c1641799369
Backout af0a7f54f483 (bug 704691), 17b4093b5ec5, 23f26ba05f1a (bug 697383) for various failures
browser/installer/package-manifest.in
dom/Makefile.in
dom/base/Makefile.in
dom/base/Webapps.js
dom/base/Webapps.jsm
dom/base/Webapps.manifest
dom/interfaces/apps/Makefile.in
dom/interfaces/apps/nsIDOMApplicationRegistry.idl
dom/interfaces/base/Makefile.in
layout/printing/nsPrintData.cpp
layout/printing/nsPrintData.h
mobile/xul/installer/package-manifest.in
toolkit/Makefile.in
toolkit/mozapps/webapps/Makefile.in
toolkit/mozapps/webapps/OpenWebapps.idl
toolkit/mozapps/webapps/OpenWebapps.js
toolkit/mozapps/webapps/OpenWebapps.jsm
toolkit/mozapps/webapps/OpenWebapps.manifest
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -129,17 +129,16 @@
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
-@BINPATH@/components/dom_apps.xpt
 @BINPATH@/components/dom_base.xpt
 @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_notification.xpt
@@ -369,18 +368,16 @@
 @BINPATH@/components/nsPrompter.manifest
 @BINPATH@/components/nsPrompter.js
 #ifdef MOZ_SERVICES_SYNC
 @BINPATH@/components/SyncComponents.manifest
 @BINPATH@/components/Weave.js
 #endif
 @BINPATH@/components/TelemetryPing.js
 @BINPATH@/components/TelemetryPing.manifest
-@BINPATH@/components/Webapps.js
-@BINPATH@/components/Webapps.manifest
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsSafebrowsingApplication.manifest
 @BINPATH@/components/nsSafebrowsingApplication.js
 @BINPATH@/components/nsURLClassifier.manifest
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -61,17 +61,16 @@ DIRS = \
   interfaces/xul \
   interfaces/storage \
   interfaces/json \
   interfaces/offline \
   interfaces/geolocation \
   interfaces/notification \
   interfaces/svg \
   interfaces/smil \
-  interfaces/apps \
   $(NULL)
 
 DIRS += \
   base \
   battery \
   sms \
   src \
   locales \
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -47,23 +47,17 @@ LIBRARY_NAME	= jsdombase_s
 LIBXUL_LIBRARY	= 1
 FORCE_STATIC_LIB = 1
 
 EXTRA_PP_COMPONENTS = \
 		ConsoleAPI.js \
 		ConsoleAPI.manifest \
 		$(NULL)
 
-EXTRA_COMPONENTS = \
-	        Webapps.js \
-	        Webapps.manifest \
-		$(NULL)
-
 EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
-                Webapps.jsm \
 		$(NULL)
 
 XPIDLSRCS = \
   nsIEntropyCollector.idl \
   nsIScriptChannel.idl \
   $(NULL)
 
 EXPORTS = \
deleted file mode 100644
--- a/dom/base/Webapps.js
+++ /dev/null
@@ -1,347 +0,0 @@
-/* ***** 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 Open Web Apps.
- *
- * 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):
- *   Fabrice Desré <fabrice@mozilla.com>
- *
- * 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 ***** */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-function WebappsRegistry() {
-  this.messages = ["Webapps:Install:Return:OK", "Webapps:Install:Return:KO",
-                   "Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO",
-                   "Webapps:Enumerate:Return:OK", "Webapps:Enumerate:Return:KO"];
-
-  this.mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
-
-  this.messages.forEach((function(msgName) {
-    this.mm.addMessageListener(msgName, this);
-  }).bind(this));
-
-  this._window = null;
-  this._id = this._getRandomId();
-  this._callbacks = [];
-}
-
-WebappsRegistry.prototype = {
-  _onerror: null,
-  _oninstall: null,
-  _onuninstall: null,
-
-  /** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest
-   * only the name property is mandatory
-   */
-  checkManifest: function(aManifest, aInstallOrigin) {
-    // TODO : check for install_allowed_from
-    if (aManifest.name == undefined)
-      return false;
-    
-    if (aManifest.installs_allowed_from) {
-      ok = false;
-      aManifest.installs_allowed_from.forEach(function(aOrigin) {
-        if (aOrigin == "*" || aOrigin == aInstallOrigin)
-          ok = true;
-      });
-      return ok;
-    }
-    return true;
-  },
-  
-  getCallbackId: function(aCallback) {
-    let id = "id" + this._getRandomId();
-    this._callbacks[id] = aCallback;
-    return id;
-  },
-  
-  getCallback: function(aId) {
-    return this._callbacks[aId];
-  },
-
-  removeCallback: function(aId) {
-    if (this._callbacks[aId])
-      delete this._callbacks[aId];
-  },
-  
-  _getRandomId: function() {
-    return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
-  },
-
-  _convertAppsArray: function(aApps) {
-    let apps = new Array();
-    for (let i = 0; i < aApps.length; i++) {
-      let app = aApps[i];
-      apps.push(new WebappsApplication(app.origin, app.manifest, app.receipt, app.installOrigin, app.installTime));
-    }
-    return apps;
-  },
-
-  set oninstall(aCallback) {
-    if (this.hasPrivileges)
-      this._oninstall = aCallback;
-    else
-      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-  },
-  
-  set onuninstall(aCallback) {
-    if (this.hasPrivileges)
-      this._onuninstall = aCallback;
-    else
-      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-  },
-
-  set onerror(aCallback) {
-    this._onerror = aCallback;
-  },
-
-  receiveMessage: function(aMessage) {
-    let msg = aMessage.json;
-    if (!(msg.oid == this._id || aMessage.name == "Webapps:Install:Return:OK" || aMessage.name == "Webapps:Uninstall:Return:OK"))
-      return
-    let app = msg.app;
-    let cb;
-    switch (aMessage.name) {
-      case "Webapps:Install:Return:OK":
-        if (this._oninstall)
-          this._oninstall.handleEvent(new WebappsApplication(app.origin, app.manifest, app.receipt,
-                                                app.installOrigin, app.installTime));
-        break;
-      case "Webapps:Install:Return:KO":
-        if (this._onerror)
-          this._onerror.handleEvent(new RegistryError(Ci.nsIDOMApplicationRegistryError.DENIED));
-        break;
-      case "Webapps:Uninstall:Return:OK":
-        if (this._onuninstall)
-          this._onuninstall.handleEvent(new WebappsApplication(msg.origin, null, null, null, 0));
-        break;
-      case "Webapps:Uninstall:Return:KO":
-        if (this._onerror)
-          this._onerror.handleEvent(new RegistryError(Ci.nsIDOMApplicationRegistryError.PERMISSION_DENIED));
-        break;
-      case "Webapps:Enumerate:Return:OK":
-        cb = this.getCallback(msg.callbackID);
-        if (cb.success) {
-          let apps = this._convertAppsArray(msg.apps);
-          cb.success.handleEvent(apps, apps.length);
-        }
-        break;
-      case "Webapps:Enumerate:Return:KO":
-        cb = this.getCallback(msg.callbackID);
-        if (cb.error)
-          cb.error.handleEvent(new RegistryError(Ci.nsIDOMApplicationRegistryError.PERMISSION_DENIED));
-        break;
-    }
-    this.removeCallback(msg.callbackID);
-  },
-  
-  _fireError: function(aCode) {
-    if (!this._onerror)
-      return;
-    this._onerror.handleEvent(new RegistryError(aCode));
-  },
-
-  _getOrigin: function(aURL) {
-    let uri = Services.io.newURI(aURL, null, null);
-    return uri.prePath; 
-  },
-
-  // nsIDOMApplicationRegistry implementation
-  
-  install: function(aURL, aReceipt) {
-    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
-    xhr.open("GET", aURL, true);
-
-    xhr.addEventListener("load", (function() {
-      if (xhr.status == 200) {
-        try {
-          let installOrigin = this._getOrigin(this._window.location.href);
-          let manifest = JSON.parse(xhr.responseText, installOrigin);
-          if (!this.checkManifest(manifest, installOrigin)) {
-            this._fireError(Ci.nsIDOMApplicationRegistryError.INVALID_MANIFEST);
-          } else {
-            this.mm.sendAsyncMessage("Webapps:Install", { app: { installOrigin: installOrigin,
-                                                          origin: this._getOrigin(aURL),
-                                                          manifest: manifest,
-                                                          receipt: aReceipt },
-                                                          from: this._window.location.href,
-                                                          oid: this._id });
-          }
-        } catch(e) {
-          this._fireError(Ci.nsIDOMApplicationRegistryError.MANIFEST_PARSE_ERROR);
-        }
-      }
-      else {
-        this._fireError(Ci.nsIDOMApplicationRegistryError.MANIFEST_URL_ERROR);
-      }      
-    }).bind(this), false);
-
-    xhr.addEventListener("error", (function() {
-      this._fireError(Ci.nsIDOMApplicationRegistryError.NETWORK_ERROR);
-    }).bind(this), false);
-
-    xhr.send(null);
-  },
-
-  uninstall: function(aOrigin) {
-    if (this.hasPrivileges)
-      this.mm.sendAsyncMessage("Webapps:Uninstall", { from: this._window.location.href,
-                                                      origin: aOrigin,
-                                                      oid: this._id });
-    else
-      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-  },
-
-  launch: function(aOrigin) {
-    this.mm.sendAsyncMessage("Webapps:Launch", { origin: aOrigin,
-                                                 from: this._window.location.href});
-  },
-  
-  enumerate: function(aSuccess, aError) {
-    this.mm.sendAsyncMessage("Webapps:Enumerate", { from: this._window.location.href,
-                                                    origin: this._getOrigin(this._window.location.href),
-                                                    oid: this._id,
-                                                    callbackID:  this.getCallbackId({ success: aSuccess, error: aError }) });
-  },
-
-  handleEvent: function(aEvent) {
-    if (aEvent.type == "unload") {
-      // remove all callbacks and event handlers so we don't call anything on a cleared scope
-      try {
-        this._oninstall = null;
-        this._onuninstall = null;
-        this._onerror = null;
-        this._callbacks = [];
-      } catch(e) {
-        dump("WebappsRegistry error:" + e + "\n");
-      }
-    }
-  },
-  
-  // nsIDOMGlobalPropertyInitializer implementation
-  init: function(aWindow) {
-    dump("DOMApplicationRegistry::init() " + aWindow + "\n");
-    this._window = aWindow;
-    this._window.addEventListener("unload", this, false);
-    this._window.appId = this._id;
-    let from = Services.io.newURI(this._window.location.href, null, null);
-    let perm = Services.perms.testExactPermission(from, "webapps-manage");
-
-    //only pages with perm set and chrome or about pages can uninstall, enumerate all set oninstall an onuninstall
-    this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION || from.schemeIs("chrome") || from.schemeIs("about");
-  },
-  
-  classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMApplicationRegistry, Ci.nsIDOMGlobalPropertyInitializer]),
-  
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
-                                    contractID: "@mozilla.org/webapps;1",
-                                    interfaces: [Ci.nsIDOMApplicationRegistry],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "Webapps Registry"})
-}
-
-function WebappsApplication(aOrigin, aManifest, aReceipt, aInstallOrigin, aInstallTime) {
-  this._origin = aOrigin;
-  this._manifest = aManifest;
-  this._receipt = aReceipt;
-  this._installOrigin = aInstallOrigin;
-  this._installTime = aInstallTime;
-}
-
-WebappsApplication.prototype = {
-  _origin: null,
-  _manifest: null,
-  _receipt: null,
-  _installOrigin: null,
-  _installTime: 0,
-
-  get origin() {
-    return this._origin;
-  },
-
-  get manifest() {
-    return this._manifest;
-  },
-
-  get receipt() {
-    return this._receipt;
-  },
-
-  get installOrigin() {
-    return this._installOrigin;
-  },
-  
-  get installTime() {
-    return this._installTime;
-  },
-
-  classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMApplication]),
-
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
-                                    contractID: "@mozilla.org/webapps/application;1",
-                                    interfaces: [Ci.nsIDOMApplication],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "Webapps Application"})
-}
-
-function RegistryError(aCode) {
-  this._code = aCode;
-}
-
-RegistryError.prototype = {
-  _code: null,
-  
-  get code() {
-    return this._code;
-  },
-  
-  classID: Components.ID("{b4937718-11a3-400b-a69f-ab442a418569}"),
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMApplicationRegistryError]),
-
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{b4937718-11a3-400b-a69f-ab442a418569}"),
-                                    contractID: "@mozilla.org/webapps/error;1",
-                                    interfaces: [Ci.nsIDOMApplicationRegistryError],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "Webapps Registry Error"})
-}
-
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, WebappsApplication, RegistryError]);
-
deleted file mode 100644
--- a/dom/base/Webapps.jsm
+++ /dev/null
@@ -1,380 +0,0 @@
-/* ***** 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 Mobile Browser.
- *
- * 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):
- *   Fabrice Desré <fabrice@mozilla.com>
- *   Mark Finkle <mfinkle@mozilla.com>
- *
- * 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 ***** */
-
-const Cu = Components.utils; 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-let EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "DOMApplicationManifest"];
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
-  Cu.import("resource://gre/modules/NetUtil.jsm");
-  return NetUtil;
-});
-
-let DOMApplicationRegistry = {
-  appsDir: null,
-  appsFile: null,
-  webapps: { },
-
-  init: function() {
-    this.mm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
-    let messages = ["Webapps:Install", "Webapps:Uninstall",
-                    "Webapps:Enumerate", "Webapps:Launch"];
-
-    messages.forEach((function(msgName) {
-      this.mm.addMessageListener(msgName, this);
-    }).bind(this));
-
-    let file =  Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
-    file.append("webapps");
-    if (!file.exists() || !file.isDirectory()) {
-      file.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-    }
-    this.appsDir = file;
-    this.appsFile = file.clone();
-    this.appsFile.append("webapps.json");
-    if (!this.appsFile.exists())
-      return;
-    
-    try {
-      let channel = NetUtil.newChannel(this.appsFile);
-      channel.contentType = "application/json";
-      let self = this;
-      NetUtil.asyncFetch(channel, function(aStream, aResult) {
-        if (!Components.isSuccessCode(aResult)) {
-          Cu.reportError("DOMApplicationRegistry: Could not read from json file " + this.appsFile.path);
-          return;
-        }
-
-        // Read json file into a string
-        let data = null;
-        try {
-          self.webapps = JSON.parse(NetUtil.readInputStreamToString(aStream, aStream.available()) || "");
-          aStream.close();
-        } catch (ex) {
-          Cu.reportError("DOMApplicationRegistry: Could not parse JSON: " + ex);
-        }
-      });
-    } catch (ex) {
-      Cu.reportError("DOMApplicationRegistry: Could not read from " + aFile.path + " : " + ex);
-    }
-  },
-
-  receiveMessage: function(aMessage) {
-    let msg = aMessage.json;
-    let from = Services.io.newURI(msg.from, null, null);
-    let perm = Services.perms.testExactPermission(from, "webapps-manage");
-
-    //only pages with perm set and chrome or about pages can uninstall, enumerate all set oninstall an onuninstall
-    let hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION || from.schemeIs("chrome") || from.schemeIs("about");
-
-    switch (aMessage.name) {
-      case "Webapps:Install":
-        // always ask for UI to install
-        Services.obs.notifyObservers(this, "webapps-ask-install", JSON.stringify(msg));
-        break;
-      case "Webapps:Uninstall":
-        if (hasPrivileges)
-          this.uninstall(msg);
-        break;
-      case "Webapps:Launch":
-        Services.obs.notifyObservers(this, "webapps-launch", JSON.stringify(msg));
-        break;
-      case "Webapps:Enumerate":
-        if (hasPrivileges)
-          this.enumerateAll(msg)
-        else
-          this.enumerate(msg);
-        break;
-    }
-  },
-
-  _writeFile: function ss_writeFile(aFile, aData, aCallbak) {
-    // Initialize the file output stream.
-    let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
-    ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN);
-
-    // Obtain a converter to convert our data to a UTF-8 encoded input stream.
-    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
-    converter.charset = "UTF-8";
-
-    // Asynchronously copy the data to the file.
-    let istream = converter.convertToInputStream(aData);
-    NetUtil.asyncCopy(istream, ostream, function(rc) {
-      if (aCallbak)
-        aCallbak();
-    });
-  },
-  
-  // clones a app object, without the manifest
-  _cloneAppObject: function(aApp) {
-    let clone = {
-      installOrigin: aApp.installOrigin,
-      origin: aApp.origin,
-      receipt: aApp.receipt,
-      installTime: aApp.installTime
-    };
-    return clone;
-  },
-  
-  denyInstall: function(aData) {
-    this.mm.sendAsyncMessage("Webapps:Install:Return:KO", aData);
-  },
-  
-  confirmInstall: function(aData) {
-    let app = aData.app;
-    let id = this._appId(app.origin);
-
-    // install an application again is considered as an update
-    if (id) {
-      let dir = this.appsDir.clone();
-      dir.append(id);
-      try {
-        dir.remove(true);
-      } catch(e) {
-      }
-    }
-    else {
-      let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-      id = uuidGenerator.generateUUID().toString();
-    }
-
-    let dir = this.appsDir.clone();
-    dir.append(id);
-    dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-    
-    let manFile = dir.clone();
-    manFile.append("manifest.json");
-    this._writeFile(manFile, JSON.stringify(app.manifest));
-
-    this.webapps[id] = this._cloneAppObject(app);
-    delete this.webapps[id].manifest;
-    this.webapps[id].installTime = (new Date()).getTime()
-
-    this._writeFile(this.appsFile, JSON.stringify(this.webapps), (function() {
-      this.mm.sendAsyncMessage("Webapps:Install:Return:OK", aData);
-    }).bind(this));
-  },
- 
-  _appId: function(aURI) {
-    for (let id in this.webapps) {
-      if (this.webapps[id].origin == aURI)
-        return id;
-    }
-    return null;
-  },
-
-  _readManifest: function(aId) {
-    let file = this.appsDir.clone();
-    file.append(aId);
-    file.append("manifest.json");
-    let data = "";  
-    let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
-    var cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
-    fstream.init(file, -1, 0, 0);
-    cstream.init(fstream, "UTF-8", 0, 0);
-    let (str = {}) {  
-      let read = 0;  
-      do {   
-        read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value  
-        data += str.value;  
-      } while (read != 0);  
-    }  
-    cstream.close(); // this closes fstream  
-    try {
-      return JSON.parse(data);
-    } catch(e) {
-      return null;
-    }
-  },
-  
-  uninstall: function(aData) {
-    for (let id in this.webapps) {
-      let app = this.webapps[id];
-      if (app.origin == aData.origin) {
-        delete this.webapps[id];
-        this._writeFile(this.appsFile, JSON.stringify(this.webapps));
-        let dir = this.appsDir.clone();
-        dir.append(id);
-        try {
-          dir.remove(true);
-        } catch (e) {
-        }
-        this.mm.sendAsyncMessage("Webapps:Uninstall:Return:OK", aData);
-      }
-    }
-  },
-  
-  enumerate: function(aData) {
-    aData.apps = [];
-
-    let id = this._appId(aData.origin);
-    // if it's an app, add itself to the result
-    if (id) {
-      let app = this._cloneAppObject(this.webapps[id]);
-      app.manifest = this._readManifest(id);
-      aData.apps.push(app);
-    }
-
-    // check if it's a store.
-    let isStore = false;
-    for (id in this.webapps) {
-      let app = this._cloneAppObject(this.webapps[id]);
-      if (app.installOrigin == aData.origin) {
-        isStore = true;
-        break;
-      }
-    }
-
-    // add all the apps from this store
-    if (isStore) {
-      for (id in this.webapps) {
-        let app = this._cloneAppObject(this.webapps[id]);
-        if (app.installOrigin == aData.origin) {
-          app.manifest = this._readManifest(id);
-          aData.apps.push(app);
-        }
-      }
-    }
-
-    this.mm.sendAsyncMessage("Webapps:Enumerate:Return:OK", aData);
-  },
-
-  denyEnumerate: function(aData) {
-    this.mm.sendAsyncMessage("Webapps:Enumerate:Return:KO", aData);
-  },
-
-  enumerateAll: function(aData) {
-    aData.apps = [];
-
-    for (id in this.webapps) {
-      let app = this._cloneAppObject(this.webapps[id]);
-      app.manifest = this._readManifest(id);
-      aData.apps.push(app);
-    }
-
-    this.mm.sendAsyncMessage("Webapps:Enumerate:Return:OK", aData);
-  },
-
-  getManifestFor: function(aOrigin) {
-    let id = this._appId(aOrigin);
-    if (!id)
-      return null;
-    return this._readManifest(id);
-  }
-};
-
-/**
- * Helper object to access manifest information with locale support
- */
-DOMApplicationManifest = function(aManifest, aOrigin) {
-  this._origin = Services.io.newURI(aOrigin, null, null);
-  this._manifest = aManifest;
-  let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry)
-                                                          .QueryInterface(Ci.nsIToolkitChromeRegistry);
-  let locale = chrome.getSelectedLocale("browser").toLowerCase();
-  this._localeRoot = this._manifest;
-  
-  if (this._manifest.locales && this._manifest.locales[locale]) {
-    this._localeRoot = this._manifest.locales[locale];
-  }
-  else if (this._manifest.locales) {
-    // try with the language part of the locale ("en" for en-GB) only
-    let lang = locale.split('-')[0];
-    if (land != locale && this._manifest.locales[lang])
-      this._localeRoot = this._manifest.locales[lang];
-  }
-}
-
-DOMApplicationManifest.prototype = {
-  _localeProp: function(aProp) {
-    if (this._localeRoot[aProp] != undefined)
-      return this._localeRoot[aProp];
-    return this._manifest[aProp];
-  },
-
-  get name() {
-    return this._localeProp("name");
-  },
-  
-  get description() {
-    return this._localeProp("description");
-  },
-  
-  get version() {
-    return this._localeProp("version");
-  },
-  
-  get launch_path() {
-    return this._localeProp("launch_path");
-  },
-  
-  get developer() {
-    return this._localeProp("developer");
-  },
-  
-  get icons() {
-    return this._localeProp("icons");
-  },
-  
-  iconURLForSize: function(aSize) {
-    let icons = this._localeProp("icons");
-    if (!icons)
-      return null;
-    let dist = 100000;
-    let icon = null;
-    for (let size in icons) {
-      let iSize = parseInt(size);
-      if (Math.abs(iSize - aSize) < dist) {
-        icon = this._origin.resolve(icons[size]);
-        dist = Math.abs(iSize - aSize);
-      }
-    }
-    return icon;
-  },
-  
-  fullLaunchPath: function() {
-    let launchPath = this._localeProp("launch_path");
-    return this._origin.resolve(launchPath ? launchPath : "");
-  }
-}
-
-DOMApplicationRegistry.init();
deleted file mode 100644
--- a/dom/base/Webapps.manifest
+++ /dev/null
@@ -1,10 +0,0 @@
-# Webapps.js
-component {fff440b3-fae2-45c1-bf03-3b5a2e432270} Webapps.js
-contract @mozilla.org/webapps;1 {fff440b3-fae2-45c1-bf03-3b5a2e432270}
-category JavaScript-navigator-property mozApps @mozilla.org/webapps;1
-
-component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js
-contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22}
-
-component {b4937718-11a3-400b-a69f-ab442a418569} Webapps.js
-contract @mozilla.org/webapps/error;1 {b4937718-11a3-400b-a69f-ab442a418569}
deleted file mode 100644
--- a/dom/interfaces/apps/Makefile.in
+++ /dev/null
@@ -1,53 +0,0 @@
-# ***** 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 web apps.
-#
-# 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):
-#  Andreas Gal <gal@mozilla.com>
-#
-# 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
-
-MODULE         = dom
-XPIDL_MODULE   = dom_apps
-GRE_MODULE     = 1
-
-XPIDLSRCS =                               \
-            nsIDOMApplicationRegistry.idl \
-            $(NULL)
-
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
+++ /dev/null
@@ -1,91 +0,0 @@
-/* ***** 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 web apps.
- *
- * 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):
- *  Andreas Gal <gal@mozilla.com>  (Original Author)
- *  Fabrice Desré <fabrice@mozilla.com>
- *
- * 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 "domstubs.idl"
-
-//interface nsIArray;
-
-[scriptable, uuid(e0c271cb-266b-48c9-a7e4-96590b445c26)]
-interface nsIDOMApplicationRegistryError : nsISupports
-{
-  const unsigned short DENIED = 1;
-  const unsigned short PERMISSION_DENIED = 2;
-  const unsigned short MANIFEST_URL_ERROR = 3;
-  const unsigned short NETWORK_ERROR = 4;
-  const unsigned short MANIFEST_PARSE_ERROR = 5;
-  const unsigned short INVALID_MANIFEST = 6;
-
-  readonly attribute short code;
-};
-
-[scriptable, uuid(a6856a3d-dece-43ce-89b9-72dba07f4246)]
-interface nsIDOMApplication : nsISupports
-{
-  readonly attribute jsval manifest;
-  readonly attribute DOMString receipt;
-  readonly attribute DOMString origin;
-  readonly attribute DOMString installOrigin;
-  readonly attribute unsigned long installTime;
-};
-
-[scriptable, function, uuid(be170df5-9154-463b-9197-10a6195eba52)]
-interface nsIDOMApplicationRegistryEnumerateCallback : nsISupports
-{
-  void handleEvent([array, size_is(count)] in nsIDOMApplication apps,
-                    in unsigned long count);
-};
-
-[scriptable, function, uuid(ae0ed33d-35cf-443a-837b-a6cebf16bd49)]
-interface nsIDOMApplicationRegistryErrorCallback : nsISupports
-{
-  void handleEvent(in nsIDOMApplicationRegistryError error);
-};
-
-[scriptable, uuid(4070ea6f-dca1-4052-8bc6-7a9bcfc314ac)]
-interface nsIDOMApplicationRegistry : nsISupports
-{
-  void install(in DOMString manifestUrl,
-	       [optional] in DOMString receipt);
-  void uninstall(in DOMString origin);
-  void enumerate(in nsIDOMApplicationRegistryEnumerateCallback success,
-		 [optional] in nsIDOMApplicationRegistryErrorCallback error);
-  void launch(in DOMString origin);
-
-  attribute nsIDOMEventListener oninstall;
-  attribute nsIDOMEventListener onuninstall;
-  attribute nsIDOMEventListener onerror;
-};
--- a/dom/interfaces/base/Makefile.in
+++ b/dom/interfaces/base/Makefile.in
@@ -52,17 +52,17 @@ SDK_XPIDLSRCS =                         
 	nsIDOMWindow.idl			\
 	nsIDOMWindowCollection.idl		\
 	nsIDOMWindowUtils.idl			\
 	$(NULL)
 
 XPIDLSRCS =					\
 	nsIFrameRequestCallback.idl             \
 	nsIBrowserDOMWindow.idl			\
-	nsIContentPermissionPrompt.idl  \
+    nsIContentPermissionPrompt.idl  \
 	nsIContentPrefService.idl		\
 	nsIContentURIGrouper.idl		\
 	nsIDOMClientInformation.idl		\
 	nsIDOMConstructor.idl			\
 	nsIDOMCRMFObject.idl			\
 	nsIDOMCrypto.idl			\
 	nsIDOMHistory.idl			\
 	nsIDOMLocation.idl			\
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -129,34 +129,35 @@ nsPrintData::~nsPrintData()
   if (mBrandName) {
     NS_Free(mBrandName);
   }
 }
 
 void nsPrintData::OnStartPrinting()
 {
   if (!mOnStartSent) {
-    DoOnProgressChange(0, 0, true, nsIWebProgressListener::STATE_START|nsIWebProgressListener::STATE_IS_DOCUMENT|nsIWebProgressListener::STATE_IS_NETWORK);
+    DoOnProgressChange(0, 0, true, nsIWebProgressListener::STATE_START|nsIWebProgressListener::STATE_IS_DOCUMENT);
     mOnStartSent = true;
   }
 }
 
 void nsPrintData::OnEndPrinting()
 {
   DoOnProgressChange(100, 100, true, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT);
-  DoOnProgressChange(100, 100, true, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_NETWORK);
 }
 
 void
-nsPrintData::DoOnProgressChange(PRInt32      aProgress,
+nsPrintData::DoOnProgressChange(PRInt32      aProgess,
                                 PRInt32      aMaxProgress,
                                 bool         aDoStartStop,
                                 PRInt32      aFlag)
 {
+  if (aProgess == 0) return;
+
   for (PRInt32 i=0;i<mPrintProgressListeners.Count();i++) {
     nsIWebProgressListener* wpl = mPrintProgressListeners.ObjectAt(i);
-    wpl->OnProgressChange(nsnull, nsnull, aProgress, aMaxProgress, aProgress, aMaxProgress);
+    wpl->OnProgressChange(nsnull, nsnull, aProgess, aMaxProgress, aProgess, aMaxProgress);
     if (aDoStartStop) {
       wpl->OnStateChange(nsnull, nsnull, aFlag, 0);
     }
   }
 }
 
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -80,17 +80,17 @@ public:
 
 
   nsPrintData(ePrintDataType aType);
   ~nsPrintData(); // non-virtual
 
   // Listener Helper Methods
   void OnEndPrinting();
   void OnStartPrinting();
-  void DoOnProgressChange(PRInt32      aProgress,
+  void DoOnProgressChange(PRInt32      aProgess,
                           PRInt32      aMaxProgress,
                           bool         aDoStartStop,
                           PRInt32      aFlag);
 
 
   ePrintDataType               mType;            // the type of data this is (Printing or Print Preview)
   nsRefPtr<nsDeviceContext>   mPrintDC;
   FILE                        *mDebugFilePtr;    // a file where information can go to when printing
--- a/mobile/xul/installer/package-manifest.in
+++ b/mobile/xul/installer/package-manifest.in
@@ -272,16 +272,17 @@
 @BINPATH@/components/xpcom_threads.xpt
 @BINPATH@/components/xpcom_xpti.xpt
 @BINPATH@/components/xpconnect.xpt
 @BINPATH@/components/xulapp.xpt
 @BINPATH@/components/xul.xpt
 @BINPATH@/components/xuldoc.xpt
 @BINPATH@/components/xultmpl.xpt
 @BINPATH@/components/zipwriter.xpt
+@BINPATH@/components/openwebapps.xpt
 
 ; JavaScript components
 @BINPATH@/components/ConsoleAPI.manifest
 @BINPATH@/components/ConsoleAPI.js
 @BINPATH@/components/FeedProcessor.manifest
 @BINPATH@/components/FeedProcessor.js
 @BINPATH@/components/BrowserFeeds.manifest
 @BINPATH@/components/FeedConverter.js
@@ -325,16 +326,17 @@
 @BINPATH@/components/GPSDGeolocationProvider.js
 @BINPATH@/components/nsSidebar.manifest
 @BINPATH@/components/nsSidebar.js
 @BINPATH@/components/extensions.manifest
 @BINPATH@/components/addonManager.js
 @BINPATH@/components/amContentHandler.js
 @BINPATH@/components/amWebInstallListener.js
 @BINPATH@/components/nsBlocklistService.js
+@BINPATH@/components/OpenWebapps.manifest
 
 #ifdef MOZ_UPDATER
 @BINPATH@/components/nsUpdateService.manifest
 @BINPATH@/components/nsUpdateService.js
 @BINPATH@/components/nsUpdateServiceStub.js
 #endif
 @BINPATH@/components/nsUpdateTimerManager.manifest
 @BINPATH@/components/nsUpdateTimerManager.js
@@ -600,16 +602,17 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/components/HelperAppDialog.js
 @BINPATH@/components/LoginManager.js
 @BINPATH@/components/LoginManagerPrompter.js
 @BINPATH@/components/MobileComponents.manifest
 @BINPATH@/components/MobileComponents.xpt
 @BINPATH@/components/PromptService.js
 @BINPATH@/components/SessionStore.js
 @BINPATH@/components/Sidebar.js
+@BINPATH@/components/OpenWebapps.js
 #ifdef MOZ_SAFE_BROWSING
 @BINPATH@/components/SafeBrowsing.js
 #endif
 #ifdef MOZ_UPDATER
 @BINPATH@/components/UpdatePrompt.js
 #endif
 @BINPATH@/components/XPIDialogService.js
 @BINPATH@/components/CapturePicker.js
--- a/toolkit/Makefile.in
+++ b/toolkit/Makefile.in
@@ -51,16 +51,17 @@ PARALLEL_DIRS = \
   locales \
   mozapps/downloads \
   mozapps/extensions \
   mozapps/handling \
   mozapps/preferences \
   mozapps/plugins \
   mozapps/shared \
   mozapps/update \
+  mozapps/webapps \
   obsolete \
   profile \
   themes \
   $(NULL)
 
 ifneq (,$(filter gtk2 qt,$(MOZ_WIDGET_TOOLKIT)))
 PARALLEL_DIRS += system/unixproxy
 endif
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/webapps/Makefile.in
@@ -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 the Open Web Apps.
+#
+# The Initial Developer of the Original Code is Ben Goodger.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Fabrice Desré <fabrice@mozilla.com>
+#
+# 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
+
+MODULE = openwebapps
+
+XPIDLSRCS = OpenWebapps.idl
+
+EXTRA_COMPONENTS += \
+  OpenWebapps.js \
+  OpenWebapps.manifest \
+  $(NULL)
+
+EXTRA_JS_MODULES = \
+  OpenWebapps.jsm \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/webapps/OpenWebapps.idl
@@ -0,0 +1,118 @@
+/* ***** 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 Open Web Apps.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Fabrice Desré <fabrice@mozilla.com>
+ *
+ * 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 ***** */
+
+// IDL for https://developer.mozilla.org/en/OpenWebApps/The_JavaScript_API
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(3b937eb5-679b-41e9-aefa-543849fa61dd)]
+interface nsIOpenWebappsApplication : nsISupports {
+    attribute jsval manifest;
+    attribute DOMString origin;
+    attribute jsval install_data;
+    attribute DOMString install_origin;
+    attribute unsigned long install_time;
+};
+
+[scriptable, function, uuid(fa3ac1bb-ad7d-44d7-8585-9ecdf3782d65)]
+interface nsIOpenWebappsSuccessInstalled : nsISupports {
+    void handle(in nsIOpenWebappsApplication application);
+};
+
+[scriptable, function, uuid(a8a83f45-4cbe-4806-b867-017554e30bd4)]
+interface nsIOpenWebappsSuccessList : nsISupports {
+    void handle([array, size_is(count)] in nsIOpenWebappsApplication apps,
+                in unsigned long count);
+};
+
+[scriptable, function, uuid(75e44e3f-ccda-4497-af68-8abd3f5e1d7b)]
+interface nsIOpenWebappsError : nsISupports {
+    attribute DOMString code;
+    attribute DOMString message;
+};
+
+[scriptable, function, uuid(8b29495e-a5e4-4e76-9af8-0f6fe97b8959)]
+interface nsIOpenWebappsErrorCB : nsISupports {
+    void handle(in nsIOpenWebappsError error);
+};
+
+[scriptable, function, uuid(b86669ab-6a36-4ceb-a4bf-a980dd496144)]
+interface nsIOpenWebappsSuccessEmpty : nsISupports {
+    void handle();
+};
+
+[scriptable, function, uuid(a458afcf-eee9-42fb-bd90-75d5e41c0d9e)]
+interface nsIOpenWebappsChangeCallback : nsISupports {
+    // what is either "add" when new apps are added to the repository, or
+    // "remove" when they are deleted.
+    void update(in DOMString what, [array, size_is(count)] in nsIOpenWebappsApplication apps,
+		in unsigned long count);
+};
+
+[scriptable, uuid(f3ec76a6-abca-4d90-b8c9-e221033068ef)]
+interface nsIOpenWebappsMgmt : nsISupports {
+    void launch(in DOMString origin,
+                [optional] in nsIOpenWebappsSuccessEmpty onsuccess,
+                [optional] in nsIOpenWebappsErrorCB onerror);
+    
+    void list(in nsIOpenWebappsSuccessList onsuccess,
+              [optional] in nsIOpenWebappsErrorCB onerror);
+    
+    void uninstall(in DOMString origin,
+                   in nsIOpenWebappsSuccessEmpty onsuccess,
+                   [optional] in nsIOpenWebappsErrorCB onerror);
+
+    long watchUpdates(in nsIOpenWebappsChangeCallback callback);
+
+    void clearWatch(in long watchId);
+};
+
+[scriptable, uuid(cecd9de7-ea4e-45fd-8a01-a5861d9109ab)]
+interface nsIOpenWebapps : nsISupports {
+    void install(in DOMString manifestURI,
+                 [optional] in jsval install_data,
+                 [optional] in nsIOpenWebappsSuccessEmpty onsuccess,
+                 [optional] in nsIOpenWebappsErrorCB onerror);
+    
+    void amInstalled(in nsIOpenWebappsSuccessInstalled onsuccess,
+                     [optional] in nsIOpenWebappsErrorCB onerror);
+    
+    void getInstalledBy(in nsIOpenWebappsSuccessList onsuccess,
+                        [optional] in nsIOpenWebappsErrorCB onerror);
+    
+    readonly attribute nsIOpenWebappsMgmt mgmt;
+};
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/webapps/OpenWebapps.js
@@ -0,0 +1,296 @@
+/* ***** 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 Open Web Apps.
+ *
+ * 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):
+ *   Fabrice Desré <fabrice@mozilla.com>
+ *
+ * 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 ***** */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+function OpenWebapps() {
+  this.messages = ["OpenWebapps:InstallDone", "OpenWebapps:InstallAborted", "OpenWebapps:GetInstalledBy:Return",
+                   "OpenWebapps:AmInstalled:Return", "OpenWebapps:MgmtLaunch:Return", "OpenWebapps:MgmtList:Return", 
+                   "OpenWebapps:MgmtUninstall:Return"];
+
+  this.mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
+
+  this.messages.forEach((function(msgName) {
+    this.mm.addMessageListener(msgName, this);
+  }).bind(this));
+
+  this._callbacks = [];
+  this._window = null;
+  this._watchId = 0;
+}
+
+OpenWebapps.prototype = {
+  
+  /** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest
+   * only the name property is mandatory
+   */
+  checkManifest: function(aManifest) {
+    return ("name" in aManifest);
+  },
+  
+  getCallbackId: function(aCallback) {
+    let id = "id" + this._getRandomId();
+    this._callbacks[id] = aCallback;
+    return id;
+  },
+  
+  getCallback: function(aId) {
+    return this._callbacks[aId];
+  },
+
+  removeCallback: function(aId) {
+    if (this._callbacks[aId])
+      delete this._callbacks[aId];
+  },
+  
+  _getRandomId: function() {
+    return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
+  },
+
+  _convertAppsArray: function(aApps) {
+    let apps = new Array();
+    for (let i = 0; i < aApps.length; i++) {
+      let app = aApps[i];
+      let xapp = Cc["@mozilla.org/openwebapps/application;1"].createInstance(Ci.nsIOpenWebappsApplication);
+      xapp.origin = app.origin;
+      xapp.manifest = app.manifest;
+      xapp.install_data = app.install_data;
+      xapp.install_origin = app.install_origin;
+      xapp.install_time = app.install_time;
+      apps.push(xapp);
+    }
+    return apps;
+  },
+
+  receiveMessage: function(aMessage) {
+    let msg = aMessage.json;
+    let callbacks = this.getCallback(msg.callbackID);
+
+    // if we have no such callback and this is not a broadcast message, bail out
+    if (!callbacks && aMessage.name != "OpenWebapps:InstallDone"
+                   && aMessage.name != "OpenWebapps:MgmtUninstall:Return")
+      return;
+
+    switch(aMessage.name) {
+      case "OpenWebapps:InstallAborted" :
+        if (callbacks.error)
+          callbacks.error.handle({ code: "denied", message: "User denied installation" });
+        break;
+      case "OpenWebapps:InstallDone" :
+        if (callbacks && callbacks.success)
+          callbacks.success.handle();
+        this._onInstalled([msg.app]);
+        break;
+      case "OpenWebapps:GetInstalledBy:Return":
+        if (callbacks && callbacks.success) {
+          let apps = this._convertAppsArray(msg.apps);
+          callbacks.success.handle(apps, apps.length);
+        }
+        break;
+      case "OpenWebapps:AmInstalled:Return":
+        if (callbacks.success)
+          callbacks.success.handle(msg.installed ? msg.app : null);
+        break;
+      case "OpenWebapps:MgmtLaunch:Return":
+        if (msg.ok && callbacks && callbacks.success)
+          callbacks.success.handle();
+        else if (!msg.ok && callbacks.error)
+          callbacks.error.handle({ code: "noSuchApp", message: "Unable to launch application"});
+        break;
+      case "OpenWebapps:MgmtList:Return":
+        if (msg.ok && callbacks && callbacks.success) {
+          let apps = this._convertAppsArray(msg.apps);
+          callbacks.success.handle(apps, apps.length);
+        }
+        else if (!msg.ok && callbacks && callbacks.error) {
+          callbacks.error.handle({ code: "noAppList", message: "Unable to get application list"});
+        }
+        break;
+      case "OpenWebapps:MgmtUninstall:Return":
+        if (msg.ok) {
+          if (callbacks && callbacks.success)
+            callbacks.success.handle();
+          this._onUninstalled([msg.app]);
+        }
+        else if (!msg.ok && callbacks.error)
+          callbacks.error.handle({ code: "noSuchApp", message: "Unable to uninstall application"});
+        break;
+    }
+    this.removeCallback(msg.callbackID);
+  },
+  
+  // nsIOpenWebapps implementation
+  
+  install: function(aURL, aInstallData, aSuccess, aError) {
+    let self = this;
+
+    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
+    xhr.open("GET", aURL, true);
+
+    xhr.addEventListener("load", function() {
+      if (xhr.status == 200) {
+        try {
+          let manifest = JSON.parse(xhr.responseText);
+          if (!self.checkManifest(manifest)) {
+            if (aError)
+              aError.handle({ code: "invalidManifest", message: "Invalid manifest" });
+          } else {
+            self.mm.sendAsyncMessage("OpenWebapps:Install", { storeURI: self._window.location.href, manifestURI: aURL, manifest: xhr.responseText,
+                             installData: aInstallData, callbackID: self.getCallbackId({ success: aSuccess, error: aError }) });
+          }
+        } catch(e) {
+          if (aError)
+            aError.handle({ code: "manifestParseError", message: "Unable to parse the manifest" });
+        }
+      }
+      else if (aError) {
+        aError.handle({ code: "networkError", message: "Unable to retrieve manifest" });
+      }      
+    }, false);
+
+    xhr.addEventListener("error", function() {
+      if (aError)
+        aError.handle({ code: "networkError", message: "Unable to retrieve manifest" });
+    }, false);
+
+    xhr.send(null);
+  },
+  
+  amInstalled: function(aSuccess, aError) {
+    this.mm.sendAsyncMessage("OpenWebapps:AmInstalled", { appURI: this._window.location.href, callbackID:  this.getCallbackId({ success: aSuccess, error: aError }) });
+  },
+  
+  getInstalledBy: function(aSuccess, aError) {
+    this.mm.sendAsyncMessage("OpenWebapps:GetInstalledBy", { storeURI: this._window.location.href, callbackID:  this.getCallbackId({ success: aSuccess, error: aError }) });
+  },
+  
+  // nsIOpenWebappsMgmt implementation
+  launch: function(aOrigin, aSuccess, aError) {
+    this.mm.sendAsyncMessage("OpenWebapps:MgmtLaunch", { origin: aOrigin, callbackID:  this.getCallbackId({ success: aSuccess, error: aError }) });
+  },
+  
+  list: function(aSuccess, aError) {
+    this.mm.sendAsyncMessage("OpenWebapps:MgmtList", { from: this._window.location.href, callbackID:  this.getCallbackId({ success: aSuccess, error: aError }) });
+  },
+  
+  uninstall: function(aOrigin, aSuccess, aError) {
+    this.mm.sendAsyncMessage("OpenWebapps:MgmtUninstall", { from: this._window.location.href, origin: aOrigin, callbackID:  this.getCallbackId({ success: aSuccess, error: aError }) });
+  },
+
+  _onRepoChange: function(aWhat, aApps) {
+    for (let prop in this._callbacks) {
+      if (this._callbacks[prop].isWatch) {
+        let apps = this._convertAppsArray(aApps);
+        this._callbacks[prop].callback.update(aWhat, apps, apps.length);
+      }
+    }
+  },
+
+  _onInstalled: function(aApps) {
+    this._onRepoChange("add", aApps);
+  },
+
+  _onUninstalled: function(aApps) {
+    this._onRepoChange("remove", aApps);
+  },
+
+  watchUpdates: function(aCallback) {
+    this._watchId++;
+    this._callbacks["_watch" + this._getRandomId()] = { isWatch: true, callback: aCallback };
+    return this._watchId;
+  },
+
+  clearWatch: function(aWatchId) {
+    this.removeCallback("_watch" + aWatchId);
+  },
+
+  handleEvent: function(aEvent) {
+    if (aEvent.type == "unload") {
+      // remove all callbacks so we don't call anything on a cleared scope
+      this._callbacks = [];
+    }
+  },
+  
+  // nsIDOMGlobalPropertyInitializer implementation
+  init: function(aWindow) {
+    this._window = aWindow;
+    this._window.addEventListener("unload", this, false);
+  },
+  
+  get mgmt() {
+    return this.QueryInterface(Ci.nsIOpenWebappsMgmt);
+  },
+  
+  classID: Components.ID("{d8fd4d63-27ea-47b9-a931-481214bb8b5b}"),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIOpenWebapps, Ci.nsIOpenWebappsMgmt, Ci.nsIDOMGlobalPropertyInitializer]),
+  
+  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{d8fd4d63-27ea-47b9-a931-481214bb8b5b}"),
+                                    contractID: "@mozilla.org/openwebapps;1",
+                                    interfaces: [Ci.nsIOpenWebapps],
+                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
+                                    classDescription: "OpenWebapps"})
+}
+
+function OpenWebappsApplication() {
+}
+
+OpenWebappsApplication.prototype = {
+  origin: null,
+  manifest: null,
+  install_data: null,
+  install_origin: null,
+  install_time: 0,
+
+  classID: Components.ID("{34456347-0792-45a4-8eb1-7b5f94f2d700}"),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIOpenWebappsApplication]),
+
+  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{34456347-0792-45a4-8eb1-7b5f94f2d700}"),
+                                    contractID: "@mozilla.org/openwebapps/application;1",
+                                    interfaces: [Ci.nsIOpenWebappsApplication],
+                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
+                                    classDescription: "OpenWebapps Application"})
+}
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([OpenWebapps, OpenWebappsApplication]);
+
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/webapps/OpenWebapps.jsm
@@ -0,0 +1,260 @@
+/* ***** 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 Mobile Browser.
+ *
+ * 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):
+ *   Fabrice Desré <fabrice@mozilla.com>
+ *   Mark Finkle <mfinkle@mozilla.com>
+ *
+ * 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 ***** */
+
+const Cu = Components.utils; 
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+let EXPORTED_SYMBOLS = ["OpenWebapps"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
+  Cu.import("resource://gre/modules/NetUtil.jsm");
+  return NetUtil;
+});
+
+let OpenWebapps = {
+  appsDir: null,
+  appsFile: null,
+  webapps: { },
+
+  init: function() {
+    let file =  Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
+    file.append("webapps");
+    if (!file.exists() || !file.isDirectory()) {
+      file.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+    }
+    this.appsDir = file;
+    this.appsFile = file.clone();
+    this.appsFile.append("webapps.json");
+    if (!this.appsFile.exists())
+      return;
+    
+    try {
+      let channel = NetUtil.newChannel(this.appsFile);
+      channel.contentType = "application/json";
+      let self = this;
+      NetUtil.asyncFetch(channel, function(aStream, aResult) {
+        if (!Components.isSuccessCode(aResult)) {
+          Cu.reportError("OpenWebappsSupport: Could not read from json file " + this.appsFile.path);
+          return;
+        }
+
+        // Read json file into a string
+        let data = null;
+        try {
+          self.webapps = JSON.parse(NetUtil.readInputStreamToString(aStream, aStream.available()) || "");
+          aStream.close();
+        } catch (ex) {
+          Cu.reportError("OpenWebsappsStore: Could not parse JSON: " + ex);
+        }
+      });
+    } catch (ex) {
+      Cu.reportError("OpenWebappsSupport: Could not read from " + aFile.path + " : " + ex);
+    }
+  },
+
+  _writeFile: function ss_writeFile(aFile, aData) {
+    // Initialize the file output stream.
+    let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+    ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN);
+
+    // Obtain a converter to convert our data to a UTF-8 encoded input stream.
+    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
+    converter.charset = "UTF-8";
+
+    // Asynchronously copy the data to the file.
+    let istream = converter.convertToInputStream(aData);
+    NetUtil.asyncCopy(istream, ostream, function(rc) {
+      // nothing to do
+    });
+  },
+  
+  install: function(aApplication) {
+    let id = this._appId(aApplication.appURI);
+
+    // install an application again is considered as an update
+    if (id) {
+      let dir = this.appsDir.clone();
+      dir.append(id);
+      try {
+        dir.remove(true);
+      } catch(e) {
+      }
+    }
+    else {
+      let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+      id = uuidGenerator.generateUUID().toString();
+    }
+
+    let dir = this.appsDir.clone();
+    dir.append(id);
+    dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+    
+    let manFile = dir.clone();
+    manFile.append("manifest.json");
+    this._writeFile(manFile, JSON.stringify(aApplication.manifest));
+    
+    this.webapps[id] = {
+      title: aApplication.title,
+      storeURI: aApplication.storeURI,
+      appURI: aApplication.appURI,
+      installData: aApplication.installData,
+      installTime: (new Date()).getTime()
+    };
+    this._writeFile(this.appsFile, JSON.stringify(this.webapps));
+
+    // now save the icon as icon.png in the app directory
+    let iconURI = aApplication.iconURI ? aApplication.iconURI : "chrome://browser/skin/images/homescreen-default-hdpi.png";
+    let iconFile = dir.clone();
+    iconFile.append("icon.png");
+    let uri = Services.io.newURI(iconURI, null, null);
+    let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
+    persist.persistFlags = persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | persist.PERSIST_FLAGS_BYPASS_CACHE;
+    persist.saveURI(uri, null, null, null, "", iconFile);
+  },
+ 
+  _appId: function(aURI) {
+    for (let id in this.webapps) {
+      if (this.webapps[id].appURI == aURI)
+        return id;
+    }
+    return null;
+  },
+
+  _readManifest: function(aId) {
+    let file = this.appsDir.clone();
+    file.append(aId);
+    file.append("manifest.json");
+    let data = "";  
+    let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
+    var cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
+    fstream.init(file, -1, 0, 0);
+    cstream.init(fstream, "UTF-8", 0, 0);
+    let (str = {}) {  
+      let read = 0;  
+      do {   
+        read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value  
+        data += str.value;  
+      } while (read != 0);  
+    }  
+    cstream.close(); // this closes fstream  
+    try {
+      return JSON.parse(data);
+    } catch(e) {
+      return null;
+    }
+  },
+
+  amInstalled: function(aURI) {
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      if (app.appURI == aURI) {
+        return { origin: app.appURI,
+                 install_origin: app.storeURI,
+                 install_data: app.installData,
+                 install_time: app.installTime,
+                 manifest: this._readManifest(id) };
+      }
+    }
+    return null;
+  },
+
+  getInstalledBy: function(aStoreURI) {
+    let res = [];
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      if (app.storeURI == aStoreURI)
+        res.push({ origin: app.appURI,
+                   install_origin: app.storeURI,
+                   install_data: app.installData,
+                   install_time: app.installTime,
+                   manifest: this._readManifest(id) });
+    }
+    return res;
+  },
+  
+  mgmtList: function() {
+    let res = new Array();
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      res.push({ origin: app.appURI,
+                 install_origin: app.storeURI,
+                 install_data: app.installData,
+                 install_time: app.installTime,
+                 manifest: this._readManifest(id) });
+    }
+    return res;
+  },
+  
+  mgmtLaunch: function(aOrigin) {
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      app.manifest = this._readManifest(id);
+      if (app.appURI == aOrigin) {
+        let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
+        let uri = Services.io.newURI(aOrigin + (app.manifest.launch_path ? app.manifest.launch_path : ""), null, null);
+        browserWin.browserDOMWindow.openURI(uri, null, browserWin.OPEN_APPTAB, Ci.nsIBrowserDOMWindow.OPEN_NEW);
+        return true;
+      }
+    }
+    return false;
+  },
+  
+  mgmtUninstall: function(aOrigin) {
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      if (app.appURI == aOrigin) {
+        delete this.webapps[id];
+        this._writeFile(this.appsFile, JSON.stringify(this.webapps));
+        let dir = this.appsDir.clone();
+        dir.append(id);
+        try {
+          dir.remove(true);
+        } catch (e) {
+        }
+        return true;
+      }
+    }
+    return false;
+  }
+};
+
+OpenWebapps.init();
+
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/webapps/OpenWebapps.manifest
@@ -0,0 +1,8 @@
+# OpenWebapps.js
+component {d8fd4d63-27ea-47b9-a931-481214bb8b5b} OpenWebapps.js
+contract @mozilla.org/openwebapps;1 {d8fd4d63-27ea-47b9-a931-481214bb8b5b}
+category JavaScript-navigator-property mozApps @mozilla.org/openwebapps;1
+
+component {34456347-0792-45a4-8eb1-7b5f94f2d700} OpenWebapps.js
+contract @mozilla.org/openwebapps/application;1 {34456347-0792-45a4-8eb1-7b5f94f2d700}
+