Bug 1341191 - WIP patch for 1341191 to fix messaging draft
authorJonathan Kingston <jkt@mozilla.com>
Tue, 28 Feb 2017 20:13:32 +0000
changeset 490562 0bc30a3691024e7f2d30e3e4c2ed61046c953016
parent 490295 e1135c6fdc9bcd80d38f7285b269e030716dcb72
child 547295 9324d6910d55d30eabe21288c0d1730800b906c8
push id47136
push userjkingston@mozilla.com
push dateTue, 28 Feb 2017 20:15:28 +0000
bugs1341191
milestone54.0a1
Bug 1341191 - WIP patch for 1341191 to fix messaging MozReview-Commit-ID: 1IcYGLAlH2Z
browser/base/content/browser-feeds.js
browser/components/feeds/FeedWriter.js
toolkit/components/feeds/FeedProcessor.js
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -1,13 +1,80 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+const PREF_SELECTED_APP = "browser.feeds.handlers.application";
+const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
+const PREF_SELECTED_ACTION = "browser.feeds.handler";
+const PREF_SELECTED_READER = "browser.feeds.handler.default";
+
+const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
+const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
+const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
+const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
+
+const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
+const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
+const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
+const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
+
+function getPrefActionForType(t) {
+  switch (t) {
+    case Ci.nsIFeed.TYPE_VIDEO:
+      return PREF_VIDEO_SELECTED_ACTION;
+
+    case Ci.nsIFeed.TYPE_AUDIO:
+      return PREF_AUDIO_SELECTED_ACTION;
+
+    default:
+      return PREF_SELECTED_ACTION;
+  }
+}
+
+function getPrefReaderForType(t) {
+  switch (t) {
+    case Ci.nsIFeed.TYPE_VIDEO:
+      return PREF_VIDEO_SELECTED_READER;
+
+    case Ci.nsIFeed.TYPE_AUDIO:
+      return PREF_AUDIO_SELECTED_READER;
+
+    default:
+      return PREF_SELECTED_READER;
+  }
+}
+
+function getPrefWebForType(t) {
+  switch (t) {
+    case Ci.nsIFeed.TYPE_VIDEO:
+      return PREF_VIDEO_SELECTED_WEB;
+
+    case Ci.nsIFeed.TYPE_AUDIO:
+      return PREF_AUDIO_SELECTED_WEB;
+
+    default:
+      return PREF_SELECTED_WEB;
+  }
+}
+
+function getPrefAppForType(t) {
+  switch (t) {
+    case Ci.nsIFeed.TYPE_VIDEO:
+      return PREF_VIDEO_SELECTED_APP;
+
+    case Ci.nsIFeed.TYPE_AUDIO:
+      return PREF_AUDIO_SELECTED_APP;
+
+    default:
+      return PREF_SELECTED_APP;
+  }
+}
+
 /**
  * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
  * and shows UI when they are discovered.
  */
 var FeedHandler = {
   /** Called when the user clicks on the Subscribe to This Page... menu item,
    * or when the user clicks the feed button when the page contains multiple
    * feeds.
@@ -218,26 +285,30 @@ var FeedHandler = {
               break;
             default:
               appName = AppConstants.MOZ_APP_NAME + "-bin";
               break;
           }
 
           if (fp.file.leafName != appName) {
             Services.prefs.setComplexValue(aPrefName, Ci.nsILocalFile, selectedApp);
-            aBrowser.messageManager.sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
-                                                    { name: this._getFileDisplayName(selectedApp),
-                                                      type: "SelectedAppMenuItem" });
+            this.setApplicationLauncherMenuItem(selectedApp, "SelectedAppMenuItem", aBrowser);
           }
         }
       }
     });
 
   },
 
+  setApplicationLauncherMenuItem(aClientApp, aType, aBrowser) {
+    aBrowser.messageManager.sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
+                                            { name: this._getFileDisplayName(aClientApp),
+                                              type: aType });
+  },
+
   executeClientApp(aSpec, aTitle, aSubtitle, aFeedHandler) {
     // aFeedHandler is either "default", indicating the system default reader, or a pref-name containing
     // an nsILocalFile pointing to the feed handler's executable.
 
     let clientApp = null;
     if (aFeedHandler == "default") {
       clientApp = Cc["@mozilla.org/browser/shell-service;1"]
                     .getService(Ci.nsIShellService)
@@ -275,36 +346,70 @@ var FeedHandler = {
       p.init(clientApp);
       p.run(false, [aSpec], 1);
     }
   },
 
   init() {
     window.messageManager.addMessageListener("FeedWriter:ChooseClientApp", this);
     window.messageManager.addMessageListener("FeedWriter:RequestClientAppName", this);
-    window.messageManager.addMessageListener("FeedWriter:SetFeedCharPref", this);
-    window.messageManager.addMessageListener("FeedWriter:SetFeedComplexString", this);
+    window.messageManager.addMessageListener("FeedWriter:SetFeedPref", this);
+    window.messageManager.addMessageListener("FeedWriter:GetAlwaysUseState", this);
+    window.messageManager.addMessageListener("FeedWriter:GetReaderForType", this);
     window.messageManager.addMessageListener("FeedWriter:ShownFirstRun", this);
 
     Services.ppmm.addMessageListener("FeedConverter:ExecuteClientApp", this);
   },
 
   uninit() {
     Services.ppmm.removeMessageListener("FeedConverter:ExecuteClientApp", this);
   },
 
   receiveMessage(msg) {
     switch (msg.name) {
+      case "FeedWriter:GetReaderForType":
+        let prefs = Services.prefs;
+        let handler = "bookmarks";
+        let url;
+        try {
+          handler = prefs.getCharPref(getPrefReaderForType(msg.data.feedType));
+        } catch (ex) { }
+
+        if (handler === "url") {
+          try {
+            url = prefs.getComplexValue(getPrefWebForType(msg.data.feedType), Ci.nsISupportsString).data;
+          } catch (ex) {
+            LOG("FeedWriter._setSelectedHandler: invalid or no handler in prefs");
+            return;
+          }
+        }
+
+        msg.target.messageManager
+           .sendAsyncMessage("FeedWriter:GetReaderForTypeResponse",
+                            { handler, url });
+        break;
+      case "FeedWriter:GetAlwaysUseState":
+        let alwaysUse = false;
+        try {
+          if (Services.prefs.getCharPref(getPrefActionForType(msg.data.feedType)) != "ask")
+            alwaysUse = true;
+        } catch (ex) { }
+        msg.target.messageManager
+           .sendAsyncMessage("FeedWriter:GetAlwaysUseStateResponse",
+                            { alwaysUse });
+        break;
       case "FeedWriter:ChooseClientApp":
-        this.chooseClientApp(msg.data.title, msg.data.prefName, msg.target);
+        const prefName = getPrefAppForType(msg.data.typeName);
+        this.chooseClientApp(msg.data.title, prefName, msg.target);
         break;
       case "FeedWriter:RequestClientAppName":
         let selectedClientApp;
+        const feedTypePref = getPrefAppForType(msg.data.feedType);
         try {
-          selectedClientApp = Services.prefs.getComplexValue(msg.data.feedTypePref, Ci.nsILocalFile);
+          selectedClientApp = Services.prefs.getComplexValue(feedTypePref, Ci.nsILocalFile);
         } catch (ex) {
           // Just do nothing, then we won't bother populating
         }
 
         let defaultClientApp = null;
         try {
           // This can sometimes not exist
           defaultClientApp = Cc["@mozilla.org/browser/shell-service;1"]
@@ -312,39 +417,50 @@ var FeedHandler = {
                                .defaultFeedReader;
         } catch (ex) {
           // Just do nothing, then we don't bother populating
         }
 
         if (selectedClientApp && selectedClientApp.exists()) {
           if (defaultClientApp && selectedClientApp.path != defaultClientApp.path) {
             // Only set the default menu item if it differs from the selected one
-            msg.target.messageManager
-               .sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
-                                { name: this._getFileDisplayName(defaultClientApp),
-                                  type: "DefaultAppMenuItem" });
+            this.setApplicationLauncherMenuItem(defaultClientApp, "DefaultAppMenuItem", msg.target);
           }
-          msg.target.messageManager
-             .sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
-                              { name: this._getFileDisplayName(selectedClientApp),
-                                type: "SelectedAppMenuItem" });
+          this.setApplicationLauncherMenuItem(selectedClientApp, "SelectedAppMenuItem", msg.target);
         }
         break;
       case "FeedWriter:ShownFirstRun":
         Services.prefs.setBoolPref("browser.feeds.showFirstRunUI", false);
         break;
-      case "FeedWriter:SetFeedCharPref":
-        Services.prefs.setCharPref(msg.data.pref, msg.data.value);
+      case "FeedWriter:SetFeedPref":
+        let pref = false;
+        let complex = false;
+        const typeName = msg.data.typeName;
+        switch (msg.data.type) {
+          case "Action":
+              pref = getPrefActionForType(typeName);
+            break;
+          case "Reader":
+              pref = getPrefReaderForType(typeName);
+            break;
+          case "Web":
+              pref = getPrefWebForType(typeName);
+              complex = true;
+            break;
+        }
+        if (pref) {
+          if (complex) {
+            let supportsString = Cc["@mozilla.org/supports-string;1"].
+                                 createInstance(Ci.nsISupportsString);
+            supportsString.data = msg.data.value;
+            Services.prefs.setComplexValue(pref, Ci.nsISupportsString, supportsString);
+          } else {
+            Services.prefs.setCharPref(pref, msg.data.value);
+          }
+        }
         break;
-      case "FeedWriter:SetFeedComplexString": {
-        let supportsString = Cc["@mozilla.org/supports-string;1"].
-                             createInstance(Ci.nsISupportsString);
-        supportsString.data = msg.data.value;
-        Services.prefs.setComplexValue(msg.data.pref, Ci.nsISupportsString, supportsString);
-        break;
-      }
       case "FeedConverter:ExecuteClientApp":
         this.executeClientApp(msg.data.spec, msg.data.title,
                               msg.data.subtitle, msg.data.feedHandler);
         break;
     }
   },
 };
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -48,88 +48,36 @@ function makeURI(aURLSpec, aCharset) {
 const XML_NS = "http://www.w3.org/XML/1998/namespace";
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const URI_BUNDLE = "chrome://browser/locale/feeds/subscribe.properties";
 
+const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
+
 const PREF_SELECTED_APP = "browser.feeds.handlers.application";
 const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
 const PREF_SELECTED_ACTION = "browser.feeds.handler";
 const PREF_SELECTED_READER = "browser.feeds.handler.default";
 
 const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
 const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
 const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
 const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
 
 const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
 const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
 const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
 const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
 
-const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
-
 const TITLE_ID = "feedTitleText";
 const SUBTITLE_ID = "feedSubtitleText";
 
-function getPrefAppForType(t) {
-  switch (t) {
-    case Ci.nsIFeed.TYPE_VIDEO:
-      return PREF_VIDEO_SELECTED_APP;
-
-    case Ci.nsIFeed.TYPE_AUDIO:
-      return PREF_AUDIO_SELECTED_APP;
-
-    default:
-      return PREF_SELECTED_APP;
-  }
-}
-
-function getPrefWebForType(t) {
-  switch (t) {
-    case Ci.nsIFeed.TYPE_VIDEO:
-      return PREF_VIDEO_SELECTED_WEB;
-
-    case Ci.nsIFeed.TYPE_AUDIO:
-      return PREF_AUDIO_SELECTED_WEB;
-
-    default:
-      return PREF_SELECTED_WEB;
-  }
-}
-
-function getPrefActionForType(t) {
-  switch (t) {
-    case Ci.nsIFeed.TYPE_VIDEO:
-      return PREF_VIDEO_SELECTED_ACTION;
-
-    case Ci.nsIFeed.TYPE_AUDIO:
-      return PREF_AUDIO_SELECTED_ACTION;
-
-    default:
-      return PREF_SELECTED_ACTION;
-  }
-}
-
-function getPrefReaderForType(t) {
-  switch (t) {
-    case Ci.nsIFeed.TYPE_VIDEO:
-      return PREF_VIDEO_SELECTED_READER;
-
-    case Ci.nsIFeed.TYPE_AUDIO:
-      return PREF_AUDIO_SELECTED_READER;
-
-    default:
-      return PREF_SELECTED_READER;
-  }
-}
-
 /**
  * Converts a number of bytes to the appropriate unit that results in a
  * number that needs fewer than 4 digits
  *
  * @return a pair: [new value with 3 sig. figs., its unit]
   */
 function convertByteUnits(aBytes) {
   let units = ["bytes", "kilobyte", "megabyte", "gigabyte"];
@@ -152,19 +100,16 @@ function convertByteUnits(aBytes) {
 function FeedWriter() {
   this._selectedApp = undefined;
   this._selectedAppMenuItem = null;
   this._subscribeCallback = null;
   this._defaultHandlerMenuItem = null;
 }
 
 FeedWriter.prototype = {
-  _mimeSvc      : Cc["@mozilla.org/mime;1"].
-                  getService(Ci.nsIMIMEService),
-
   _getPropertyAsBag(container, property) {
     return container.fields.getProperty(property).
                      QueryInterface(Ci.nsIPropertyBag2);
   },
 
   _getPropertyAsString(container, property) {
     try {
       return container.fields.getPropertyAsAString(property);
@@ -490,27 +435,21 @@ FeedWriter.prototype = {
       enclosureDiv.setAttribute("class", "enclosure");
 
       let mozicon = "moz-icon://.txt?size=16";
       let type_text = null;
       let size_text = null;
 
       if (enc.hasKey("type")) {
         type_text = enc.get("type");
-        try {
-          let handlerInfoWrapper = this._mimeSvc.getFromTypeAndExtension(enc.get("type"), null);
-
-          if (handlerInfoWrapper)
-            type_text = handlerInfoWrapper.description;
+        if (enc.hasKey("typeDesc"))
+          type_text = enc.get("typeDesc");
 
-          if (type_text && type_text.length > 0)
-            mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type");
-
-        } catch (ex) { }
-
+        if (type_text && type_text.length > 0)
+          mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type");
       }
 
       if (enc.hasKey("length") && /^[0-9]+$/.test(enc.get("length"))) {
         let enc_size = convertByteUnits(parseInt(enc.get("length")));
 
         size_text = this._getFormattedString("enclosureSizeText",
                                              [enc_size[0],
                                              this._getString(enc_size[1])]);
@@ -595,29 +534,22 @@ FeedWriter.prototype = {
    * Displays a prompt from which the user may choose a (client) feed reader.
    * @param aCallback the callback method, passes in true if a feed reader was
    *        selected, false otherwise.
    */
   _chooseClientApp(aCallback) {
     this._subscribeCallback = aCallback;
     this._mm.sendAsyncMessage("FeedWriter:ChooseClientApp",
                               { title: this._getString("chooseApplicationDialogTitle"),
-                                prefName: getPrefAppForType(this._getFeedType()) });
+                                typeName: this._getFeedType() });
   },
 
   _setAlwaysUseCheckedState(feedType) {
-    let checkbox = this._document.getElementById("alwaysUse");
-    if (checkbox) {
-      let alwaysUse = false;
-      try {
-        if (Services.prefs.getCharPref(getPrefActionForType(feedType)) != "ask")
-          alwaysUse = true;
-      } catch (ex) { }
-      this._setCheckboxCheckedState(checkbox, alwaysUse);
-    }
+    this._mm.sendAsyncMessage("FeedWriter:GetAlwaysUseState",
+                              { feedType });
   },
 
   _setSubscribeUsingLabel() {
     let stringLabel = "subscribeFeedUsing";
     switch (this._getFeedType()) {
       case Ci.nsIFeed.TYPE_VIDEO:
         stringLabel = "subscribeVideoPodcastUsing";
         break;
@@ -686,39 +618,30 @@ FeedWriter.prototype = {
         } else {
           this._setAlwaysUseLabel();
         }
         break;
     }
   },
 
   _getWebHandlerElementsForURL(aURL) {
-    let menu = this._document.getElementById("handlersMenuList");
-    return menu.querySelectorAll('[webhandlerurl="' + aURL + '"]');
+    return this._handlersList.querySelectorAll('[webhandlerurl="' + aURL + '"]');
   },
 
   _setSelectedHandler(feedType) {
-    let prefs = Services.prefs;
-    let handler = "bookmarks";
-    try {
-      handler = prefs.getCharPref(getPrefReaderForType(feedType));
-    } catch (ex) { }
+    this._mm.sendAsyncMessage("FeedWriter:GetReaderForType",
+                              { feedType });
+  },
 
-    switch (handler) {
+  _setSelectedHandlerResponse(msg) {
+    switch (msg.data.handler) {
       case "web": {
         if (this._handlersList) {
-          let url;
-          try {
-            url = prefs.getComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString).data;
-          } catch (ex) {
-            LOG("FeedWriter._setSelectedHandler: invalid or no handler in prefs");
-            return;
-          }
           let handlers =
-            this._getWebHandlerElementsForURL(url);
+            this._getWebHandlerElementsForURL(msg.data.url);
           if (handlers.length == 0) {
             LOG("FeedWriter._setSelectedHandler: selected web handler isn't in the menulist")
             return;
           }
 
           handlers[0].selected = true;
         }
         break;
@@ -732,18 +655,17 @@ FeedWriter.prototype = {
         let liveBookmarksMenuItem = this._document.getElementById("liveBookmarksMenuItem");
         if (liveBookmarksMenuItem)
           liveBookmarksMenuItem.selected = true;
       }
     }
   },
 
   _initSubscriptionUI() {
-    let handlersList = this._document.getElementById("handlersMenuList");
-    if (!handlersList)
+    if (!this._handlersList)
       return;
 
     let feedType = this._getFeedType();
 
     // change the background
     let header = this._document.getElementById("feedHeader");
     switch (feedType) {
       case Ci.nsIFeed.TYPE_VIDEO:
@@ -765,75 +687,75 @@ FeedWriter.prototype = {
     menuItem.removeAttribute("selected");
     menuItem.setAttribute("id", "selectedAppMenuItem");
     menuItem.setAttribute("handlerType", "client");
 
     // Hide the menuitem until we select an app
     menuItem.style.display = "none";
     this._selectedAppMenuItem = menuItem;
 
-    handlersList.appendChild(this._selectedAppMenuItem);
+    this._handlersList.appendChild(this._selectedAppMenuItem);
 
     // Create the menuitem for the default reader, but don't show/populate it until
     // we get confirmation of what it is from the parent
     menuItem = liveBookmarksMenuItem.cloneNode(false);
     menuItem.removeAttribute("selected");
     menuItem.setAttribute("id", "defaultHandlerMenuItem");
     menuItem.setAttribute("handlerType", "client");
     menuItem.style.display = "none";
 
     this._defaultHandlerMenuItem = menuItem;
-    handlersList.appendChild(this._defaultHandlerMenuItem);
+    this._handlersList.appendChild(this._defaultHandlerMenuItem);
 
     this._mm.sendAsyncMessage("FeedWriter:RequestClientAppName",
-                              { feedTypePref: getPrefAppForType(feedType) });
+                              { feedType });
 
     // "Choose Application..." menuitem
     menuItem = liveBookmarksMenuItem.cloneNode(false);
     menuItem.removeAttribute("selected");
     menuItem.setAttribute("id", "chooseApplicationMenuItem");
     menuItem.textContent = this._getString("chooseApplicationMenuItem");
 
-    handlersList.appendChild(menuItem);
+    this._handlersList.appendChild(menuItem);
 
     // separator
     let chooseAppSep = liveBookmarksMenuItem.nextElementSibling.cloneNode(false);
     chooseAppSep.textContent = liveBookmarksMenuItem.nextElementSibling.textContent;
-    handlersList.appendChild(chooseAppSep);
+    this._handlersList.appendChild(chooseAppSep);
 
     // List of web handlers
     let wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
                getService(Ci.nsIWebContentConverterService);
     let handlers = wccr.getContentHandlers(this._getMimeTypeForFeedType(feedType));
     for (let handler of handlers) {
       if (!handler.uri) {
         LOG("Handler with name " + handler.name + " has no URI!? Skipping...");
         continue;
       }
       menuItem = liveBookmarksMenuItem.cloneNode(false);
       menuItem.removeAttribute("selected");
       menuItem.className = "menuitem-iconic";
       menuItem.textContent = handler.name;
       menuItem.setAttribute("handlerType", "web");
       menuItem.setAttribute("webhandlerurl", handler.uri);
-      handlersList.appendChild(menuItem);
+      this._handlersList.appendChild(menuItem);
     }
 
     this._setSelectedHandler(feedType);
 
     // "Subscribe using..."
     this._setSubscribeUsingLabel();
 
     // "Always use..." checkbox initial state
     this._setAlwaysUseCheckedState(feedType);
     this._setAlwaysUseLabel();
 
     // We update the "Always use.." checkbox label whenever the selected item
     // in the list is changed
-    handlersList.addEventListener("change", this);
+    this._handlersList.addEventListener("change", this);
 
     // Set up the "Subscribe Now" button
     this._document.getElementById("subscribeButton")
         .addEventListener("click", this);
 
     // first-run ui
     let showFirstRunUI = true;
     try {
@@ -938,20 +860,36 @@ FeedWriter.prototype = {
     prefs.addObserver(PREF_VIDEO_SELECTED_APP, this, false);
 
     prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, false);
     prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, false);
     prefs.addObserver(PREF_AUDIO_SELECTED_WEB, this, false);
     prefs.addObserver(PREF_AUDIO_SELECTED_APP, this, false);
 
     this._mm.addMessageListener("FeedWriter:SetApplicationLauncherMenuItem", this);
+    this._mm.addMessageListener("FeedWriter:GetAlwaysUseStateResponse", this);
+    this._mm.addMessageListener("FeedWriter:GetReaderForTypeResponse", this);
   },
 
   receiveMessage(msg) {
+    if (!this._window) {
+      // this._window is null unless this.init was called with a trusted
+      // window object.
+      return;
+    }
     switch (msg.name) {
+      case "FeedWriter:GetReaderForTypeResponse":
+        this._setSelectedHandlerResponse(msg);
+        break;
+      case "FeedWriter:GetAlwaysUseStateResponse":
+        let checkbox = this._document.getElementById("alwaysUse");
+        if (msg.data.alwaysUse && checkbox) {
+          this._setCheckboxCheckedState(checkbox, msg.data.alwaysUse);
+        }
+        break;
       case "FeedWriter:SetApplicationLauncherMenuItem":
         let menuItem = null;
 
         if (msg.data.type == "DefaultAppMenuItem") {
           menuItem = this._defaultHandlerMenuItem;
         } else {
           // Most likely SelectedAppMenuItem
           menuItem = this._selectedAppMenuItem;
@@ -988,17 +926,17 @@ FeedWriter.prototype = {
     } finally {
       this._removeFeedFromCache();
     }
   },
 
   close() {
     this._document.getElementById("subscribeButton")
         .removeEventListener("click", this);
-    this._document.getElementById("handlersMenuList")
+    this._handlersList
         .removeEventListener("change", this);
     this._document = null;
     this._window = null;
     let prefs = Services.prefs;
     prefs.removeObserver(PREF_SELECTED_ACTION, this);
     prefs.removeObserver(PREF_SELECTED_READER, this);
     prefs.removeObserver(PREF_SELECTED_WEB, this);
     prefs.removeObserver(PREF_SELECTED_APP, this);
@@ -1025,44 +963,36 @@ FeedWriter.prototype = {
     if (this._feedURI) {
       let feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
                         getService(Ci.nsIFeedResultService);
       feedService.removeFeedResult(this._feedURI);
       this._feedURI = null;
     }
   },
 
-  setFeedCharPref(aPrefName, aPrefValue) {
-      this._mm.sendAsyncMessage("FeedWriter:SetFeedCharPref",
-                                { pref: aPrefName,
-                                  value: aPrefValue });
-  },
-
-  setFeedComplexString(aPrefName, aPrefValue) {
-      // This sends the string data across to the parent, which will use it in an nsISupportsString
-      // for a complex value pref.
-      this._mm.sendAsyncMessage("FeedWriter:SetFeedComplexString",
-                                { pref: aPrefName,
+  setFeedPref(aType, aTypeName, aPrefValue) {
+      this._mm.sendAsyncMessage("FeedWriter:SetFeedPref",
+                                { type: aType,
+                                  typeName: aTypeName,
                                   value: aPrefValue });
   },
 
   subscribe() {
     let feedType = this._getFeedType();
 
     // Subscribe to the feed using the selected handler and save prefs
     let defaultHandler = "reader";
     let useAsDefault = this._document.getElementById("alwaysUse").getAttribute("checked");
 
-    let menuList = this._document.getElementById("handlersMenuList");
-    let selectedItem = menuList.selectedOptions[0];
+    let selectedItem = this._handlersList.selectedOptions[0];
     let subscribeCallback = () => {
       if (selectedItem.hasAttribute("webhandlerurl")) {
         let webURI = selectedItem.getAttribute("webhandlerurl");
-        this.setFeedCharPref(getPrefReaderForType(feedType), "web");
-        this.setFeedComplexString(getPrefWebForType(feedType), webURI);
+        this.setFeedPref("Reader", feedType, "web");
+        this.setFeedPref("Web", feedType, webURI);
 
         let wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
                    getService(Ci.nsIWebContentConverterService);
         let handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI);
         if (handler) {
           if (useAsDefault) {
             wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler);
           }
@@ -1079,42 +1009,43 @@ FeedWriter.prototype = {
             feedReader = "default";
             break;
           case "liveBookmarksMenuItem":
             defaultHandler = "bookmarks";
             feedReader = "bookmarks";
             break;
         }
 
-        this.setFeedCharPref(getPrefReaderForType(feedType), feedReader);
+        this.setFeedPref("Reader", feedType, feedReader);
 
         let feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
                           getService(Ci.nsIFeedResultService);
 
         // Pull the title and subtitle out of the document
         let feedTitle = this._document.getElementById(TITLE_ID).textContent;
         let feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent;
         feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType, feedReader);
       }
 
       // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
       // to either "reader" (If a web reader or if an application is selected),
       // or to "bookmarks" (if the live bookmarks option is selected).
       // Otherwise, we should set it to "ask"
-      if (useAsDefault) {
-        this.setFeedCharPref(getPrefActionForType(feedType), defaultHandler);
-      } else {
-        this.setFeedCharPref(getPrefActionForType(feedType), "ask");
+      if (!useAsDefault) {
+        defaultHandler = "ask";
       }
+      this.setFeedPref("Action", feedType, defaultHandler);
     }
 
     // Show the file picker before subscribing if the
     // choose application menuitem was chosen using the keyboard
     if (selectedItem.id == "chooseApplicationMenuItem") {
       this._chooseClientApp(function(aResult) {
+        // JKTODO establish if this is even working at all?!
+        LOG("AM I EVER CALLED JKTODO");
         if (aResult) {
           selectedItem =
             this._handlersList.selectedOptions[0];
           subscribeCallback();
         }
       }.bind(this));
     } else {
       subscribeCallback();
--- a/toolkit/components/feeds/FeedProcessor.js
+++ b/toolkit/components/feeds/FeedProcessor.js
@@ -37,17 +37,17 @@ const PERSON_CLASSID = Components.ID("{9
 const PERSON_CLASSNAME = "Feed Person";
 
 const IO_CONTRACTID = "@mozilla.org/network/io-service;1"
 const BAG_CONTRACTID = "@mozilla.org/hash-property-bag;1"
 const ARRAY_CONTRACTID = "@mozilla.org/array;1";
 const SAX_CONTRACTID = "@mozilla.org/saxparser/xmlreader;1";
 const PARSERUTILS_CONTRACTID = "@mozilla.org/parserutils;1";
 
-
+const gMimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
 var gIoService = null;
 
 const XMLNS = "http://www.w3.org/XML/1998/namespace";
 const RSS090NS = "http://my.netscape.com/rdf/simple/0.9/";
 
 /** *** Some general utils *****/
 function strToURI(link, base) {
   base = base || null;
@@ -479,18 +479,25 @@ Entry.prototype = {
     if (this.__enclosure_map == null)
       this.__enclosure_map = {};
 
     var previous_enc = this.__enclosure_map[new_enc.getPropertyAsAString("url")];
 
     if (previous_enc != undefined) {
       previous_enc.QueryInterface(Ci.nsIWritablePropertyBag2);
 
-      if (!bagHasKey(previous_enc, "type") && bagHasKey(new_enc, "type"))
+      if (!bagHasKey(previous_enc, "type") && bagHasKey(new_enc, "type")) {
         previous_enc.setPropertyAsAString("type", new_enc.getPropertyAsAString("type"));
+        try {
+          let handlerInfoWrapper = gMimeService.getFromTypeAndExtension(new_enc.getPropertyAsAString("type"), null);
+          if (handlerInfoWrapper && handlerInfoWrapper.description) {
+            previous_enc.setPropertyAsAString("typeDesc", handlerInfoWrapper.description);
+          }
+        } catch (ext) {}
+      }
 
       if (!bagHasKey(previous_enc, "length") && bagHasKey(new_enc, "length"))
         previous_enc.setPropertyAsAString("length", new_enc.getPropertyAsAString("length"));
 
       return;
     }
 
     if (this.enclosures == null) {