Bug 1466705 - Backed out changeset ec2cc16327fe which was pushed accidentally. a=backout DONTBUILD
authorJorg K <jorgk@jorgk.com>
Fri, 15 Jun 2018 19:50:15 +0200
changeset 32213 f41fe8a63f2b280c03c69a1ea4945b77a182bcbb
parent 32212 d4e700bab1b134447fdb27f9676e43e3f15931a8
child 32214 5ebc1943af38cbb9e33bb9fa19de2441be7bff9f
push id385
push userclokep@gmail.com
push dateTue, 04 Sep 2018 23:26:14 +0000
reviewersbackout
bugs1466705
Bug 1466705 - Backed out changeset ec2cc16327fe which was pushed accidentally. a=backout DONTBUILD
mailnews/base/content/subscribe.js
mailnews/base/public/nsISubscribableServer.idl
mailnews/base/src/nsSubscribableServer.cpp
mailnews/base/src/nsSubscribableServer.h
mailnews/imap/src/nsImapIncomingServer.cpp
mailnews/news/src/nsNntpIncomingServer.cpp
--- a/mailnews/base/content/subscribe.js
+++ b/mailnews/base/content/subscribe.js
@@ -13,20 +13,22 @@ var gChangeTable = {};
 var gServerURI = null;
 var gSubscribableServer = null;
 var gNameField = null;
 var gNameFieldLabel = null;
 var gStatusFeedback;
 var gSubscribeDeck = null;
 var gSearchView = null;
 var gSearchTreeBoxObject = null;
+var gItemsFound = new Map();
 var gSubscribeBundle;
 
 function Stop()
 {
+  //dump("Stop()\n")
   if (gSubscribableServer) {
     gSubscribableServer.stopPopulating(msgWindow);
   }
 }
 
 function SetServerTypeSpecificTextValues()
 {
   if (!gServerURI)
@@ -52,62 +54,115 @@ function onServerClick(aFolder)
   let serverMenu = document.getElementById("serverMenu");
   serverMenu.menupopup.selectFolder(aFolder);
 
   SetServerTypeSpecificTextValues();
   ShowCurrentList();
 }
 
 var MySubscribeListener = {
+  OnItemDiscovered: function(aPath, aSubscribable) {
+    if (!gItemsFound.has(aPath))
+      gItemsFound.set(aPath, gSubscribableServer.getLeafName(aPath));
+  },
+
   OnDonePopulating: function() {
+    createSubscribeTree();
     gStatusFeedback._stopMeteors();
     document.getElementById("stopButton").disabled = true;
+
+// XXX what does this do? Is this needed without RDF/template?
+    // Only re-root the tree, if it is null.
+    // Otherwise, we are in here because we are populating a part of the tree.
+/*    let refValue = gSubscribeTree.getAttribute('ref');
+    if (!refValue) {
+      //dump("root subscribe tree at: "+ gServerURI +"\n");
+      gSubscribeTree.database.AddDataSource(subscribeDS);
+      gSubscribeTree.setAttribute('ref',gServerURI);
+    }
+*/
+
     document.getElementById("refreshButton").disabled = false;
     document.getElementById("currentListTab").disabled = false;
     document.getElementById("newGroupsTab").disabled = false;
   }
 };
 
+function setSubscribableCellState(aSubscribeCell, aSubscribed, aSubscribable) {
+  aSubscribeCell.setAttribute("properties", "subscribed-" + aSubscribed +
+                                            " subscribable-" + aSubscribable);
+  aSubscribeCell.setAttribute("value", aSubscribed);
+}
+
+/**
+ * Populate the subscribe tree with the items found on the server.
+ */
+function createSubscribeTree() {
+  let items = toArray(gItemsFound.entries());
+  items.sort((a,b) => a[0].localeCompare(b[0]));
+
+  for (let [path, name] of items) {
+    let subscribed = gSubscribableServer.isSubscribed(path);
+    let subscribable = gSubscribableServer.isSubscribable(path);
+    let itemEl = document.createElement("treeitem");
+    let rowEl = document.createElement("treerow");
+    let nameEl = document.createElement("treecell");
+    let subscribeEl = document.createElement("treecell");
+    nameEl.setAttribute("label", name);
+    nameEl.setAttribute("value", path);
+    nameEl.setAttribute("properties", "serverType-" + gSubscribableServer.type +
+                                      " subscribable-" + subscribable);
+    setSubscribableCellState(subscribeEl, subscribed, subscribable);
+    rowEl.appendChild(nameEl);
+    rowEl.appendChild(subscribeEl);
+    itemEl.appendChild(rowEl);
+    gSubscribeBody.appendChild(itemEl);
+ }
+}
+
 function SetUpTree(forceToServer, getOnlyNew)
 {
   if (!gServerURI)
     return;
 
   var server = MailUtils.getFolderForURI(gServerURI, true).server;
   try
   {
     CleanUpSearchView();
     gSubscribableServer = server.QueryInterface(Ci.nsISubscribableServer);
+    gSubscribeTree.setAttribute('ref', ''); // XXX: what is this?
 
     // enable (or disable) the search related UI
     EnableSearchUI();
 
     // clear out the text field when switching server
     gNameField.value = "";
 
     // since there is no text, switch to the non-search view...
     SwitchToNormalView();
 
-    if (!gSubscribableServer.subscribeListener) {
-      gSubscribeTree.view = gSubscribableServer.folderView;
-      gSubscribableServer.subscribeListener = MySubscribeListener;
-    }
+    // Clear the subscribe tree.
+    while (gSubscribeBody.hasChildNodes())
+      gSubscribeBody.lastChild.remove();
+
+    gSubscribableServer.subscribeListener = MySubscribeListener;
 
     var currentListTab = document.getElementById("currentListTab");
     if (currentListTab.selected)
       document.getElementById("newGroupsTab").disabled = true;
     else
       currentListTab.disabled = true;
 
     document.getElementById("refreshButton").disabled = true;
 
     gStatusFeedback._startMeteors();
     gStatusFeedback.showStatusString(gSubscribeBundle.getString("pleaseWaitString"));
     document.getElementById("stopButton").removeAttribute("disabled");
 
+    gItemsFound.clear();
     gSubscribableServer.startPopulating(msgWindow, forceToServer, getOnlyNew);
   }
   catch (ex)
   {
     dump("failed to populate subscribe ds: " + ex + "\n");
   }
 }
 
@@ -131,16 +186,17 @@ function EnableSearchUI()
   else {
     gNameField.setAttribute('disabled',true);
     gNameFieldLabel.setAttribute('disabled',true);
   }
 }
 
 function SubscribeOnLoad()
 {
+  //dump("SubscribeOnLoad()\n");
   gSubscribeBundle = document.getElementById("bundle_subscribe");
 
   gSubscribeTree = document.getElementById("subscribeTree");
   gSubscribeBody = document.getElementById("subscribeTreeBody");
   gSearchTree = document.getElementById("searchTree");
   gSearchTreeBoxObject = document.getElementById("searchTree").treeBoxObject;
   gNameField = document.getElementById("namefield");
   gNameFieldLabel = document.getElementById("namefieldlabel");
@@ -203,16 +259,17 @@ function SubscribeOnLoad()
 
   ShowCurrentList();
 
   gNameField.focus();
 }
 
 function subscribeOK()
 {
+  //dump("in subscribeOK()\n")
   if (top.okCallback) {
     top.okCallback(top.gChangeTable);
   }
   Stop();
   if (gSubscribableServer) {
     gSubscribableServer.subscribeCleanup();
   }
   return true;
@@ -222,21 +279,42 @@ function subscribeCancel()
 {
   Stop();
   if (gSubscribableServer) {
     gSubscribableServer.subscribeCleanup();
   }
   return true;
 }
 
-function SetState(name, state)
+function SetState(name, state, aRow)
 {
   var changed = gSubscribableServer.setState(name, state);
   if (changed)
     StateChanged(name, state);
+
+  let subscribeCell;
+  if (aRow === undefined) {
+    // XXX This won't work when multiple levels of children are implemented
+    for (let row of gSubscribeBody.children) {
+      if (row.children[0].children[0].getAttribute("value") == name) {
+        subscribeCell = row;
+        break;
+      }
+    }
+  } else {
+    subscribeCell = gSubscribeBody.children[aRow];
+  }
+  setSubscribableCellState(subscribeCell.children[0].children[1], state, true);
+}
+
+function changeTableRecord(server, name, state)
+{
+  this.server = server;
+  this.name = name;
+  this.state = state;
 }
 
 function StateChanged(name,state)
 {
   if (gServerURI in gChangeTable) {
     if (name in gChangeTable[gServerURI]) {
       var oldValue = gChangeTable[gServerURI][name];
       if (oldValue != state)
@@ -335,16 +413,17 @@ function SetSubscribeState(state)
   catch (ex) {
     dump("SetSubscribedState failed:  " + ex + "\n");
   }
 }
 
 function ReverseStateFromNode(row)
 {
   let name = gSubscribeTree.view.getCellValue(row, gSubscribeTree.columns["nameColumn"]);
+
   SetState(name, !gSubscribableServer.isSubscribed(name), row);
 }
 
 function SubscribeOnClick(event)
 {
   // we only care about button 0 (left click) events
   if (event.button != 0 || event.originalTarget.localName != "treechildren")
    return;
@@ -359,19 +438,31 @@ function SubscribeOnClick(event)
     // that isn't a container
     if (!gSubscribeTree.view.isContainer(row.value)) {
       ReverseStateFromNode(row.value);
       return;
     }
   }
   else if (event.detail == 1)
   {
-    // if the user single clicks on the subscribe check box, we handle it here
-    if (col.value.id == "subscribedColumn")
-      ReverseStateFromNode(row.value);
+    if (obj.value == "twisty") {
+        if (gSubscribeTree.view.isContainerOpen(row.value)) {
+          var uri = gSubscribeTree.builderView.getResourceAtIndex(row.value).Value;
+
+          gStatusFeedback._startMeteors();
+          gStatusFeedback.showStatusString(gSubscribeBundle.getString("pleaseWaitString"));
+
+          gSubscribableServer.startPopulatingWithUri(msgWindow, true /* force to server */, uri);
+        }
+    }
+    else {
+      // if the user single clicks on the subscribe check box, we handle it here
+      if (col.value.id == "subscribedColumn")
+        ReverseStateFromNode(row.value);
+    }
   }
 }
 
 function Refresh()
 {
   // clear out the textfield's entry
   gNameField.value = "";
 
--- a/mailnews/base/public/nsISubscribableServer.idl
+++ b/mailnews/base/public/nsISubscribableServer.idl
@@ -5,32 +5,28 @@
 
 #include "nsISupports.idl"
 
 interface nsIMsgWindow;
 interface nsIMsgIncomingServer;
 interface nsIRDFResource;
 interface nsIRDFNode;
 interface nsISimpleEnumerator;
-interface nsITreeView;
 
 [scriptable, uuid(61a08c3a-1dd2-11b2-b64f-c4b2de1cf129)]
 interface nsISubscribeDataSource : nsISupports {
     readonly attribute boolean hasObservers;
     void NotifyObservers(in nsIRDFResource subject, in nsIRDFResource property, in nsIRDFNode object, in boolean isAssert, in boolean isChange);
 };
 
-/**
- * A listener to receive notification of the subscribable folders of a server.
- */
 [scriptable, uuid(f337b84a-1dd1-11b2-97c7-fb8b2e3f2280)]
 interface nsISubscribeListener : nsISupports {
-  /**
-   * The server has finished finding all folders to subscribe to.
-   */
+  // Announce a new item found on the server.
+  void OnItemDiscovered(in AUTF8String aPath, in boolean aSubscribable);
+  // Announce finish of discovering server items.
   void OnDonePopulating();
 };
 
 [scriptable, uuid(14b8597a-755b-4e93-b364-e0903801e6ea)]
 interface nsISubscribableServer : nsISupports {
   attribute nsISubscribeListener subscribeListener;
   attribute char delimiter;
 
@@ -74,11 +70,10 @@ interface nsISubscribableServer : nsISup
    */
   nsISimpleEnumerator getChildren(in AUTF8String aPath);
   // if path is null, use the root
   AUTF8String getFirstChildURI(in AUTF8String path);
 
   // for searching
   void setSearchValue(in AString searchValue);
   readonly attribute boolean supportsSubscribeSearch;
-  readonly attribute nsITreeView folderView;
 };
 
--- a/mailnews/base/src/nsSubscribableServer.cpp
+++ b/mailnews/base/src/nsSubscribableServer.cpp
@@ -9,27 +9,25 @@
 #include "rdf.h"
 #include "nsRDFCID.h"
 #include "nsIServiceManager.h"
 #include "nsMsgI18N.h"
 #include "nsMsgUtils.h"
 #include "nsCOMArray.h"
 #include "nsArrayEnumerator.h"
 #include "nsServiceManagerUtils.h"
-#include "nsTreeColumns.h"
-#include "mozilla/dom/DataTransfer.h"
 
 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
 
 nsSubscribableServer::nsSubscribableServer(void)
 {
     mDelimiter = '.';
     mShowFullName = true;
     mTreeRoot = nullptr;
-    mStopped = true;
+    mStopped = false;
 }
 
 nsresult
 nsSubscribableServer::Init()
 {
     nsresult rv;
 
     rv = EnsureRDFService();
@@ -48,46 +46,42 @@ nsSubscribableServer::Init()
 
     rv = mRDFService->GetLiteral(u"false", getter_AddRefs(kFalseLiteral));
     NS_ENSURE_SUCCESS(rv,rv);
     return NS_OK;
 }
 
 nsSubscribableServer::~nsSubscribableServer(void)
 {
-  mozilla::DebugOnly<nsresult> rv = FreeRows();
-  NS_ASSERTION(NS_SUCCEEDED(rv), "failed to free tree rows");
-  rv = FreeSubtree(mTreeRoot);
+  mozilla::DebugOnly<nsresult> rv = FreeSubtree(mTreeRoot);
   NS_ASSERTION(NS_SUCCEEDED(rv),"failed to free tree");
 }
 
-NS_IMPL_ISUPPORTS(nsSubscribableServer, nsISubscribableServer, nsITreeView)
+NS_IMPL_ISUPPORTS(nsSubscribableServer, nsISubscribableServer)
 
 NS_IMETHODIMP
 nsSubscribableServer::SetIncomingServer(nsIMsgIncomingServer *aServer)
 {
   if (!aServer) {
     mIncomingServerUri.AssignLiteral("");
-    mServerType.Truncate();
     return NS_OK;
   }
-  aServer->GetType(mServerType);
 
   // We intentionally do not store a pointer to the aServer here
   // as it would create reference loops, because nsIImapIncomingServer
   // and nsINntpIncomingServer keep a reference to an internal
   // nsISubscribableServer object.
   // We only need the URI of the server anyway.
   return aServer->GetServerURI(mIncomingServerUri);
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::GetDelimiter(char *aDelimiter)
 {
-  NS_ENSURE_ARG_POINTER(aDelimiter);
+  if (!aDelimiter) return NS_ERROR_NULL_POINTER;
   *aDelimiter = mDelimiter;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::SetDelimiter(char aDelimiter)
 {
   mDelimiter = aDelimiter;
@@ -100,53 +94,61 @@ nsSubscribableServer::SetAsSubscribed(co
     nsresult rv = NS_OK;
 
     SubscribeTreeNode *node = nullptr;
     rv = FindAndCreateNode(path, &node);
     NS_ENSURE_SUCCESS(rv,rv);
 
     NS_ASSERTION(node,"didn't find the node");
     if (!node) return NS_ERROR_FAILURE;
+
     node->isSubscribable = true;
     node->isSubscribed = true;
 
     rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed);
     NS_ENSURE_SUCCESS(rv,rv);
 
     return rv;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::AddTo(const nsACString& aName, bool aAddAsSubscribed,
                             bool aSubscribable, bool aChangeIfExists)
 {
     nsresult rv = NS_OK;
 
     if (mStopped) {
+#ifdef DEBUG_seth
+        printf("stopped!\n");
+#endif
         return NS_ERROR_FAILURE;
     }
 
     SubscribeTreeNode *node = nullptr;
 
     // todo, shouldn't we pass in aAddAsSubscribed, for the
     // default value if we create it?
     rv = FindAndCreateNode(aName, &node);
     NS_ENSURE_SUCCESS(rv,rv);
+
     NS_ASSERTION(node,"didn't find the node");
     if (!node) return NS_ERROR_FAILURE;
 
     if (aChangeIfExists) {
         node->isSubscribed = aAddAsSubscribed;
         rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed);
         NS_ENSURE_SUCCESS(rv,rv);
     }
 
     node->isSubscribable = aSubscribable;
 
-    return NS_OK;
+    if (mSubscribeListener)
+        mSubscribeListener->OnItemDiscovered(aName, aSubscribable);
+
+    return rv;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::SetState(const nsACString &aPath, bool aState,
                                bool *aStateChanged)
 {
     nsresult rv = NS_OK;
     NS_ASSERTION(!aPath.IsEmpty() && aStateChanged, "no path or stateChanged");
@@ -172,17 +174,18 @@ nsSubscribableServer::SetState(const nsA
         return NS_OK;
     }
     else {
         node->isSubscribed = aState;
         *aStateChanged = true;
         rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed);
         NS_ENSURE_SUCCESS(rv,rv);
     }
-    return NS_OK;
+
+    return rv;
 }
 
 void
 nsSubscribableServer::BuildURIFromNode(SubscribeTreeNode *node, nsACString &uri)
 {
     if (node->parent) {
         BuildURIFromNode(node->parent, uri);
         if (node->parent == mTreeRoot) {
@@ -326,17 +329,17 @@ nsSubscribableServer::SetSubscribeListen
 {
   mSubscribeListener = aListener;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::GetSubscribeListener(nsISubscribeListener **aListener)
 {
-  NS_ENSURE_ARG_POINTER(aListener);
+  if (!aListener) return NS_ERROR_NULL_POINTER;
   NS_IF_ADDREF(*aListener = mSubscribeListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::SubscribeCleanup()
 {
   NS_ASSERTION(false,"override this.");
@@ -348,62 +351,31 @@ nsSubscribableServer::StartPopulatingWit
 {
     mStopped = false;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::StartPopulating(nsIMsgWindow *aMsgWindow, bool aForceToServer, bool aGetOnlyNew /*ignored*/)
 {
-    mStopped = false;
+    nsresult rv = NS_OK;
 
-    nsresult rv = FreeRows();
-    NS_ENSURE_SUCCESS(rv, rv);
+    mStopped = false;
 
     rv = FreeSubtree(mTreeRoot);
     mTreeRoot = nullptr;
     NS_ENSURE_SUCCESS(rv,rv);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::StopPopulating(nsIMsgWindow *aMsgWindow)
 {
-  if (mStopped)
-    return NS_OK;
-
-  mStopped = true;
-
-  NS_ASSERTION(mRowMap.Length() == 0, "mRowMap should be empty");
-  if (!mTreeRoot)
+    mStopped = true;
     return NS_OK;
-
-  SubscribeTreeNode *node = mTreeRoot->lastChild;
-  // Add top level items as closed.
-  while (node)
-  {
-    node->isOpen = false;
-    mRowMap.AppendElement(node);
-    node = node->prevSibling;
-  }
-
-  // Invalidate the whole thing.
-  if (mTree)
-    mTree->RowCountChanged(0, mRowMap.Length());
-
-  // Open all the top level items if they are containers.
-  uint32_t topRows = mRowMap.Length();
-  for (int32_t i = topRows - 1; i >= 0; i--) {
-    bool isContainer = false;
-    IsContainer(i, &isContainer);
-    if (isContainer)
-      ToggleOpenState(i);
-  }
-
-  return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsSubscribableServer::UpdateSubscribed()
 {
   NS_ASSERTION(false,"override this.");
   return NS_ERROR_FAILURE;
@@ -458,48 +430,34 @@ nsSubscribableServer::FreeSubtree(Subscr
         free(node->name);
 #if 0
         node->name = nullptr;
         node->parent = nullptr;
         node->lastChild = nullptr;
         node->cachedChild = nullptr;
 #endif
 
-        delete node;
+        PR_Free(node);
     }
 
     return NS_OK;
 }
 
 nsresult
-nsSubscribableServer::FreeRows()
-{
-  int32_t rowCount = mRowMap.Length();
-  mRowMap.Clear();
-  if (mTree)
-    mTree->RowCountChanged(0, -rowCount);
-
-  return NS_OK;
-}
-
-nsresult
-nsSubscribableServer::CreateNode(SubscribeTreeNode *parent, const char *name, const nsACString &aPath, SubscribeTreeNode **result)
+nsSubscribableServer::CreateNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **result)
 {
     NS_ASSERTION(result && name, "result or name is null");
-    NS_ENSURE_ARG_POINTER(result);
-    NS_ENSURE_ARG_POINTER(name);
+    if (!result || !name) return NS_ERROR_NULL_POINTER;
 
-    *result = new SubscribeTreeNode();
+    *result = (SubscribeTreeNode *) PR_Malloc(sizeof(SubscribeTreeNode));
     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
 
     (*result)->name = strdup(name);
     if (!(*result)->name) return NS_ERROR_OUT_OF_MEMORY;
 
-    (*result)->path.Assign(aPath);
-
     (*result)->parent = parent;
     (*result)->prevSibling = nullptr;
     (*result)->nextSibling = nullptr;
     (*result)->firstChild = nullptr;
     (*result)->lastChild = nullptr;
     (*result)->isSubscribed = false;
     (*result)->isSubscribable = false;
 #ifdef HAVE_SUBSCRIBE_DESCRIPTION
@@ -509,31 +467,29 @@ nsSubscribableServer::CreateNode(Subscri
     (*result)->messages = 0;
 #endif
     (*result)->cachedChild = nullptr;
 
     if (parent) {
         parent->cachedChild = *result;
     }
 
-    (*result)->isOpen = true;
-
     return NS_OK;
 }
 
 nsresult
-nsSubscribableServer::AddChildNode(SubscribeTreeNode *parent, const char *name, const nsACString &aPath, SubscribeTreeNode **child)
+nsSubscribableServer::AddChildNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **child)
 {
     nsresult rv = NS_OK;
-    NS_ASSERTION(parent && child && name && !aPath.IsEmpty(), "parent, child or name is null");
-    if (!parent || !child || !name || aPath.IsEmpty()) return NS_ERROR_NULL_POINTER;
+    NS_ASSERTION(parent && child && name, "parent, child or name is null");
+    if (!parent || !child || !name) return NS_ERROR_NULL_POINTER;
 
     if (!parent->firstChild) {
         // CreateNode will set the parent->cachedChild
-        rv = CreateNode(parent, name, aPath, child);
+        rv = CreateNode(parent, name, child);
         NS_ENSURE_SUCCESS(rv,rv);
 
         parent->firstChild = *child;
         parent->lastChild = *child;
 
         rv = NotifyAssert(parent, kNC_Child, *child);
         NS_ENSURE_SUCCESS(rv,rv);
 
@@ -562,17 +518,17 @@ nsSubscribableServer::AddChildNode(Subsc
      * we can efficiently reverse the order when dumping to hostinfo.dat
      * or to GetTargets()
      */
     int32_t compare = strcmp(current->name, name);
 
     while (current && (compare != 0)) {
         if (compare < 0) {
             // CreateNode will set the parent->cachedChild
-            rv = CreateNode(parent, name, aPath, child);
+            rv = CreateNode(parent, name, child);
             NS_ENSURE_SUCCESS(rv,rv);
 
             (*child)->nextSibling = current;
             (*child)->prevSibling = current->prevSibling;
             current->prevSibling = (*child);
             if (!(*child)->prevSibling) {
                 parent->firstChild = (*child);
             }
@@ -599,17 +555,17 @@ nsSubscribableServer::AddChildNode(Subsc
         *child = current;
 
         // set the cachedChild
         parent->cachedChild = *child;
         return NS_OK;
     }
 
     // CreateNode will set the parent->cachedChild
-    rv = CreateNode(parent, name, aPath, child);
+    rv = CreateNode(parent, name, child);
     NS_ENSURE_SUCCESS(rv,rv);
 
     (*child)->prevSibling = parent->lastChild;
     (*child)->nextSibling = nullptr;
     parent->lastChild->nextSibling = *child;
     parent->lastChild = *child;
 
     rv = NotifyAssert(parent, kNC_Child, *child);
@@ -618,81 +574,85 @@ nsSubscribableServer::AddChildNode(Subsc
 }
 
 nsresult
 nsSubscribableServer::FindAndCreateNode(const nsACString &aPath,
                                         SubscribeTreeNode **aResult)
 {
   nsresult rv = NS_OK;
   NS_ASSERTION(aResult, "no result");
-  NS_ENSURE_ARG_POINTER(aResult);
+  if (!aResult) return NS_ERROR_NULL_POINTER;
 
   if (!mTreeRoot) {
       // the root has no parent, and its name is server uri
-      rv = CreateNode(nullptr, mIncomingServerUri.get(), EmptyCString(), &mTreeRoot);
+      rv = CreateNode(nullptr, mIncomingServerUri.get(), &mTreeRoot);
       NS_ENSURE_SUCCESS(rv,rv);
   }
 
   if (aPath.IsEmpty()) {
       *aResult = mTreeRoot;
       return NS_OK;
   }
 
+  char *token = nullptr;
+  nsCString pathStr(aPath);
+  char *rest = pathStr.BeginWriting();
+
+  // todo do this only once
+  char delimstr[2];
+  delimstr[0] = mDelimiter;
+  delimstr[1] = '\0';
+
   *aResult = nullptr;
 
   SubscribeTreeNode *parent = mTreeRoot;
   SubscribeTreeNode *child = nullptr;
 
-  uint32_t tokenStart = 0;
-  // Special case paths that start with the hierarchy delimiter.
+  token = NS_strtok(delimstr, &rest);
+  // special case paths that start with the hierarchy delimiter.
   // We want to include that delimiter in the first token name.
-  // So start from position 1.
-  int32_t tokenEnd = aPath.FindChar(mDelimiter, tokenStart + 1);
-  while (true) {
-    if (tokenEnd == kNotFound) {
-      if (tokenStart >= aPath.Length())
-        break;
-      tokenEnd = aPath.Length();
-    }
-    nsCString token(Substring(aPath, tokenStart, tokenEnd - tokenStart));
-    rv = AddChildNode(parent, token.BeginReading(), Substring(aPath, 0, tokenEnd), &child);
+  if (token && pathStr[0] == mDelimiter)
+    --token;
+  while (token && *token) {
+    rv = AddChildNode(parent, token, &child);
     if (NS_FAILED(rv))
       return rv;
-    tokenStart = tokenEnd + 1;
-    tokenEnd = aPath.FindChar(mDelimiter, tokenStart);
+    token = NS_strtok(delimstr, &rest);
     parent = child;
   }
 
   // the last child we add is the result
   *aResult = child;
   return rv;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::HasChildren(const nsACString &aPath, bool *aHasChildren)
 {
+    nsresult rv = NS_OK;
     NS_ASSERTION(aHasChildren, "no hasChildren");
-    NS_ENSURE_ARG_POINTER(aHasChildren);
+    if (!aHasChildren) return NS_ERROR_NULL_POINTER;
 
     *aHasChildren = false;
 
     SubscribeTreeNode *node = nullptr;
-    nsresult rv = FindAndCreateNode(aPath, &node);
+    rv = FindAndCreateNode(aPath, &node);
     NS_ENSURE_SUCCESS(rv,rv);
 
     NS_ASSERTION(node,"didn't find the node");
     if (!node) return NS_ERROR_FAILURE;
 
     *aHasChildren = (node->firstChild != nullptr);
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
-nsSubscribableServer::IsSubscribed(const nsACString &aPath, bool *aIsSubscribed)
+nsSubscribableServer::IsSubscribed(const nsACString &aPath,
+                                   bool *aIsSubscribed)
 {
     NS_ENSURE_ARG_POINTER(aIsSubscribed);
 
     *aIsSubscribed = false;
 
     SubscribeTreeNode *node = nullptr;
     nsresult rv = FindAndCreateNode(aPath, &node);
     NS_ENSURE_SUCCESS(rv,rv);
@@ -837,372 +797,8 @@ nsSubscribableServer::SetSearchValue(con
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsSubscribableServer::GetSupportsSubscribeSearch(bool *retVal)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
-
-NS_IMETHODIMP
-nsSubscribableServer::GetFolderView(nsITreeView **aView)
-{
-  NS_ENSURE_ARG_POINTER(aView);
-  return this->QueryInterface(NS_GET_IID(nsITreeView), (void**)aView);
-}
-
-int32_t
-nsSubscribableServer::GetRow(SubscribeTreeNode *node, bool *open)
-{
-  int32_t parentRow = -1;
-  if (node->parent)
-    parentRow = GetRow(node->parent, open);
-
-  // If the parent wasn't opened, we're not in the row map
-  if (open && *open == false)
-    return -1;
-
-  if (open)
-    *open = node->isOpen;
-
-  for (uint32_t row = parentRow + 1; row < mRowMap.Length(); row++)
-  {
-    if (mRowMap[row] == node)
-      return row;
-  }
-
-  // Apparently, we're not in the map
-  return -1;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetSelection(nsITreeSelection **selection)
-{
-  NS_IF_ADDREF(*selection = mSelection);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::SetSelection(nsITreeSelection *selection)
-{
-  mSelection = selection;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetRowCount(int32_t *rowCount)
-{
-  *rowCount = mRowMap.Length();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::SetTree(nsITreeBoxObject *aTree)
-{
-  mTree = aTree;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsContainer(int32_t aIndex, bool *retval)
-{
-  *retval = !!mRowMap[aIndex]->firstChild;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsContainerEmpty(int32_t aIndex, bool *retval)
-{
-  *retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsContainerOpen(int32_t aIndex, bool *retval)
-{
-  *retval = mRowMap[aIndex]->isOpen;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetParentIndex(int32_t aIndex, int32_t *retval)
-{
-  SubscribeTreeNode *parent = mRowMap[aIndex]->parent;
-  if (!parent)
-  {
-    *retval = -1;
-    return NS_OK;
-  }
-
-  int32_t index;
-  for (index = aIndex - 1; index >= 0; index--)
-  {
-    if (mRowMap[index] == parent)
-    {
-      *retval = index;
-      return NS_OK;
-    }
-  }
-  *retval = -1;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex,
-                                     bool *retval)
-{
-  // This looks odd, but is correct. Using ->nextSibling gives a bad tree.
-  *retval = !!mRowMap[aRowIndex]->prevSibling;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetLevel(int32_t aIndex, int32_t *retval)
-{
-  // When starting with -2, we increase twice and return 0 for a top level node.
-  int32_t level = -2;
-  SubscribeTreeNode *node = mRowMap[aIndex];
-  while (node)
-  {
-    node = node->parent;
-    level++;
-  }
-
-  *retval = level;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::ToggleOpenState(int32_t aIndex)
-{
-  SubscribeTreeNode *node = mRowMap[aIndex];
-  if (node->isOpen)
-  {
-    // Close the node by finding the next sibling
-    node->isOpen = false;
-    int32_t count = node->prevSibling
-      ? (mRowMap.IndexOf(node->prevSibling, aIndex) - aIndex - 1)
-      : (mRowMap.Length() - aIndex - 1);
-    mRowMap.RemoveElementsAt(aIndex + 1, count);
-    if (mTree)
-    {
-      mTree->RowCountChanged(aIndex + 1, -count);
-      mTree->InvalidateRow(aIndex);
-    }
-  }
-  else
-  {
-    // Recursively add the children nodes (i.e., remember open)
-    node->isOpen = true;
-    int32_t total = 0;
-    node = node->lastChild;
-    while (node)
-    {
-      total += AddSubtree(node, aIndex + 1 + total);
-      node = node->prevSibling;
-    }
-    if (mTree)
-    {
-      mTree->RowCountChanged(aIndex + 1, total);
-      mTree->InvalidateRow(aIndex);
-    }
-  }
-  return NS_OK;
-}
-
-int32_t
-nsSubscribableServer::AddSubtree(SubscribeTreeNode *node, int32_t index)
-{
-  mRowMap.InsertElementAt(index, node);
-  int32_t total = 1;
-  if (node->isOpen)
-  {
-    node = node->lastChild;
-    while (node)
-    {
-      total += AddSubtree(node, index + total);
-      node = node->prevSibling;
-    }
-  }
-  return total;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetCellText(int32_t aRow, nsTreeColumn *aCol,
-                                  nsAString &retval)
-{
-  nsString colId;
-  aCol->GetId(colId);
-  if (colId.EqualsLiteral("nameColumn")) {
-    nsCString path(mRowMap[aRow]->path);
-    GetLeafName(path, retval);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetCellValue(int32_t aRow, nsTreeColumn *aCol,
-                                   nsAString &retval)
-{
-  nsString colId;
-  aCol->GetId(colId);
-  if (colId.EqualsLiteral("nameColumn"))
-    retval = NS_ConvertUTF8toUTF16(mRowMap[aRow]->path);
-  if (colId.EqualsLiteral("subscribedColumn"))
-  {
-    retval = mRowMap[aRow]->isSubscribed ? NS_LITERAL_STRING("true")
-                                         : NS_LITERAL_STRING("false");
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::SetCellText(int32_t aRow, nsTreeColumn *aCol,
-                                  const nsAString &aText)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::SetCellValue(int32_t aRow, nsTreeColumn *aCol,
-                                   const nsAString &aText)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetCellProperties(int32_t aRow, nsTreeColumn *aCol,
-                                        nsAString& aProps)
-{
-  SubscribeTreeNode *node = mRowMap[aRow];
-  if (node->isSubscribable)
-    aProps.AssignLiteral("subscribable-true");
-  else
-    aProps.AssignLiteral("subscribable-false");
-
-  nsString colId;
-  aCol->GetId(colId);
-  if (colId.EqualsLiteral("subscribedColumn")) {
-    if (node->isSubscribed)
-      aProps.AppendLiteral(" subscribed-true");
-    else
-      aProps.AppendLiteral(" subscribed-false");
-  } else if (colId.EqualsLiteral("nameColumn")) {
-    aProps.AppendLiteral(" serverType-");
-    aProps.Append(NS_ConvertUTF8toUTF16(mServerType));
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetRowProperties(int32_t aRow, nsAString& aProps)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetColumnProperties(nsTreeColumn *aCol,
-                                          nsAString& aProps)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsEditable(int32_t aRow, nsTreeColumn *aCol,
-                                 bool *retval)
-{
-  *retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsSelectable(int32_t aRow, nsTreeColumn *aCol,
-                                   bool *retval)
-{
-  *retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsSeparator(int32_t aRowIndex, bool *retval)
-{
-  *retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::IsSorted(bool *retval)
-{
-  *retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::CanDrop(int32_t aIndex, int32_t aOrientation,
-                              mozilla::dom::DataTransfer *aData, bool *retval)
-{
-  *retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::Drop(int32_t aRow, int32_t aOrientation,
-                           mozilla::dom::DataTransfer *aData)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::GetImageSrc(int32_t aRow, nsTreeColumn *aCol,
-                                  nsAString &retval)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::CycleHeader(nsTreeColumn *aCol)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::SelectionChanged()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::CycleCell(int32_t aRow, nsTreeColumn *aCol)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::PerformAction(const char16_t *aAction)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::PerformActionOnRow(const char16_t *aAction, int32_t aRow)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSubscribableServer::PerformActionOnCell(const char16_t *aAction,
-                                          int32_t aRow, nsTreeColumn *aCol)
-{
-  return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS(nsSubscribeListener, nsISubscribeListener)
-
-nsSubscribeListener::~nsSubscribeListener(void)
-{
-}
-
-NS_IMETHODIMP
-nsSubscribeListener::OnDonePopulating()
-{
-  return NS_OK;
-}
--- a/mailnews/base/src/nsSubscribableServer.h
+++ b/mailnews/base/src/nsSubscribableServer.h
@@ -3,105 +3,78 @@
  * 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/. */
 
 #ifndef nsSubscribableServer_h__
 #define nsSubscribableServer_h__
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
-#include "nsIMsgIncomingServer.h"
-#include "nsITreeBoxObject.h"
-#include "nsITreeSelection.h"
-#include "nsITreeView.h"
 #include "nsISubscribableServer.h"
 #include "nsIRDFService.h"
 #include "nsSubscribeDataSource.h"
 #include "nsIRDFResource.h"
-#include "nsTArray.h"
 
-/**
- * The basic structure for the tree of the implementation.
- *
- * These elements are stored in reverse alphabetical order.
- */
 typedef struct _subscribeTreeNode {
   char *name;
-  nsCString path;
   bool isSubscribed;
   struct _subscribeTreeNode *prevSibling;
   struct _subscribeTreeNode *nextSibling;
   struct _subscribeTreeNode *firstChild;
   struct _subscribeTreeNode *lastChild;
   struct _subscribeTreeNode *parent;
   struct _subscribeTreeNode *cachedChild;
 #ifdef HAVE_SUBSCRIBE_DESCRIPTION
   char16_t *description;
 #endif
 #ifdef HAVE_SUBSCRIBE_MESSAGES
   uint32_t messages;
 #endif
   bool isSubscribable;
-  bool isOpen;
 } SubscribeTreeNode;
 
+#if defined(DEBUG_sspitzer) || defined(DEBUG_seth)
+#define DEBUG_SUBSCRIBE 1
+#endif
 
-class nsSubscribableServer : public nsISubscribableServer,
-                             public nsITreeView
+class nsSubscribableServer : public nsISubscribableServer
 {
-public:
+ public:
   nsSubscribableServer();
 
   nsresult Init();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSISUBSCRIBABLESERVER
-  NS_DECL_NSITREEVIEW
 
 private:
   virtual ~nsSubscribableServer();
 
   nsresult ConvertNameToUnichar(const char *inStr, char16_t **outStr);
   nsCOMPtr <nsISubscribeListener> mSubscribeListener;
   nsCString mIncomingServerUri;
   nsCOMPtr <nsISubscribeDataSource> mSubscribeDS;
   char mDelimiter;
   bool mShowFullName;
   bool mStopped;
-  nsCString mServerType;
 
   nsCOMPtr <nsIRDFResource>      kNC_Child;
   nsCOMPtr <nsIRDFResource>      kNC_Subscribed;
   nsCOMPtr <nsIRDFLiteral>       kTrueLiteral;
   nsCOMPtr <nsIRDFLiteral>       kFalseLiteral;
 
   nsCOMPtr <nsIRDFService>       mRDFService;
 
-  SubscribeTreeNode *mTreeRoot;          // root of the folder tree while items are discovered on the server
-  nsTArray<SubscribeTreeNode*> mRowMap;  // array of nodes representing the rows for the tree element
-  nsCOMPtr<nsITreeSelection> mSelection;
-  nsCOMPtr<nsITreeBoxObject> mTree;
+  SubscribeTreeNode *mTreeRoot;
   nsresult FreeSubtree(SubscribeTreeNode *node);
-  nsresult FreeRows();
-  nsresult CreateNode(SubscribeTreeNode *parent, const char *name, const nsACString &aPath, SubscribeTreeNode **result);
-  nsresult AddChildNode(SubscribeTreeNode *parent, const char *name, const nsACString &aPath, SubscribeTreeNode **child);
-  nsresult FindAndCreateNode(const nsACString &aPath, SubscribeTreeNode **aResult);
+  nsresult CreateNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **result);
+  nsresult AddChildNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **child);
+  nsresult FindAndCreateNode(const nsACString &aPath,
+                             SubscribeTreeNode **aResult);
   nsresult NotifyAssert(SubscribeTreeNode *subjectNode, nsIRDFResource *property, SubscribeTreeNode *objectNode);
   nsresult NotifyChange(SubscribeTreeNode *subjectNode, nsIRDFResource *property, bool value);
   nsresult Notify(nsIRDFResource *subject, nsIRDFResource *property, nsIRDFNode *object, bool isAssert, bool isChange);
   void BuildURIFromNode(SubscribeTreeNode *node, nsACString &uri);
   nsresult EnsureSubscribeDS();
   nsresult EnsureRDFService();
-
-  int32_t GetRow(SubscribeTreeNode *node, bool *open);
-  int32_t AddSubtree(SubscribeTreeNode *node, int32_t index);
-};
-
-class nsSubscribeListener : public nsISubscribeListener
-{
-public:
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSISUBSCRIBELISTENER
-private:
-  virtual ~nsSubscribeListener();
 };
 
 #endif // nsSubscribableServer_h__
--- a/mailnews/imap/src/nsImapIncomingServer.cpp
+++ b/mailnews/imap/src/nsImapIncomingServer.cpp
@@ -2987,24 +2987,16 @@ NS_IMETHODIMP
 nsImapIncomingServer::GetSupportsSubscribeSearch(bool *retVal)
 {
   NS_ENSURE_ARG_POINTER(retVal);
   *retVal = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsImapIncomingServer::GetFolderView(nsITreeView **aView)
-{
-  nsresult rv = EnsureInner();
-  NS_ENSURE_SUCCESS(rv,rv);
-  return mInner->GetFolderView(aView);
-}
-
-NS_IMETHODIMP
 nsImapIncomingServer::GetFilterScope(nsMsgSearchScopeValue *filterScope)
 {
   NS_ENSURE_ARG_POINTER(filterScope);
   // If the inbox is enabled for offline use, then use the offline filter
   // scope, else use the online filter scope.
   //
   // XXX We use the same scope for all folders with the same incoming server,
   // yet it is possible to set the offline flag separately for each folder.
--- a/mailnews/news/src/nsNntpIncomingServer.cpp
+++ b/mailnews/news/src/nsNntpIncomingServer.cpp
@@ -1691,24 +1691,16 @@ nsNntpIncomingServer::SetSearchValue(con
 NS_IMETHODIMP
 nsNntpIncomingServer::GetSupportsSubscribeSearch(bool *retVal)
 {
   *retVal = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNntpIncomingServer::GetFolderView(nsITreeView **aView)
-{
-  nsresult rv = EnsureInner();
-  NS_ENSURE_SUCCESS(rv,rv);
-  return mInner->GetFolderView(aView);
-}
-
-NS_IMETHODIMP
 nsNntpIncomingServer::GetRowCount(int32_t *aRowCount)
 {
   *aRowCount = mSubscribeSearchResult.Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNntpIncomingServer::GetSelection(nsITreeSelection * *aSelection)