/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyGetter(this, "cpmm", function() { return Cc["@mozilla.org/childprocessmessagemanager;1"] .getService(Ci.nsIMessageSender); }); function debug(aMsg) { //dump("--*-- ContentHandler: " + aMsg + "\n"); } const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; let ActivityContentFactory = { createInstance: function createInstance(outer, iid) { if (outer != null) { throw Cr.NS_ERROR_NO_AGGREGATION; } return new ActivityContentHandler().QueryInterface(iid); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]) } function ActivityContentHandler() { } ActivityContentHandler.prototype = { handleContent: function handleContent(aMimetype, aContext, aRequest) { if (!(aRequest instanceof Ci.nsIChannel)) throw NS_ERROR_WONT_HANDLE_CONTENT; let detail = { "type": aMimetype, "url": aRequest.URI.spec }; cpmm.sendAsyncMessage("content-handler", detail); aRequest.cancel(Cr.NS_BINDING_ABORTED); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]) } function ContentHandler() { this.classIdMap = {}; } ContentHandler.prototype = { observe: function(aSubject, aTopic, aData) { if (aTopic == "app-startup") { // We only want to register these from content processes. let appInfo = Cc["@mozilla.org/xre/app-info;1"]; if (appInfo.getService(Ci.nsIXULRuntime) .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { return; } } cpmm.addMessageListener("Activities:RegisterContentTypes", this); cpmm.addMessageListener("Activities:UnregisterContentTypes", this); cpmm.sendAsyncMessage("Activities:GetContentTypes", { }); }, /** * Do the component registration for a content type. * We only need to register one component per content type, even if several * apps provide it, so we keep track of the number of providers for each * content type. */ registerContentHandler: function registerContentHandler(aContentType) { debug("Registering " + aContentType); // We already have a provider for this content type, just increase the // tracking count. if (this.classIdMap[aContentType]) { this.classIdMap[aContentType].count++; return; } let contractID = "@mozilla.org/uriloader/content-handler;1?type=" + aContentType; let uuidGen = Cc["@mozilla.org/uuid-generator;1"] .getService(Ci.nsIUUIDGenerator); let id = Components.ID(uuidGen.generateUUID().toString()); this.classIdMap[aContentType] = { count: 1, id: id }; let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); cr.registerFactory(Components.ID(id), "Activity Content Handler", contractID, ActivityContentFactory); }, /** * Do the component unregistration for a content type. */ unregisterContentHandler: function registerContentHandler(aContentType) { debug("Unregistering " + aContentType); let record = this.classIdMap[aContentType]; if (!record) { return; } // Bail out if we still have providers left for this content type. if (--record.count > 0) { return; } let contractID = "@mozilla.org/uriloader/content-handler;1?type=" + aContentType; let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); cr.unregisterFactory(record.id, ActivityContentFactory); delete this.classIdMap[aContentType] }, receiveMessage: function(aMessage) { let data = aMessage.data; switch (aMessage.name) { case "Activities:RegisterContentTypes": data.contentTypes.forEach(this.registerContentHandler, this); break; case "Activities:UnregisterContentTypes": data.contentTypes.forEach(this.unregisterContentHandler, this); break; } }, classID: Components.ID("{d18d0216-d50c-11e1-ba54-efb18d0ef0ac}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler, Ci.nsIObserver, Ci.nsISupportsWeakReference]) }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentHandler]);