Bug 226890 - Thunderbird doesn't handle news URIs properly, part 10: Make command-line news handling work. r=bienvenu, sr=neil
authorJoshua Cranmer <Pidgeot18@gmail.com>
Mon, 21 Nov 2011 18:12:42 -0600
changeset 9887 e57a9c880238b71e2c87144402cbfe5e7d709f7c
parent 9886 874d9533b2d8444d93929e4dd30b9c82b1df4fd3
child 9888 fac3f825a13b57fb0bbf5b59d9b23ac74a5aa9fb
push id336
push userbugzilla@standard8.plus.com
push dateTue, 31 Jan 2012 22:15:45 +0000
treeherdercomm-beta@54945f5d278d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbienvenu, neil
bugs226890
Bug 226890 - Thunderbird doesn't handle news URIs properly, part 10: Make command-line news handling work. r=bienvenu, sr=neil
mail/components/nsMailDefaultHandler.js
mailnews/base/util/nsMsgProtocol.cpp
mailnews/news/src/nsNntpIncomingServer.cpp
mailnews/news/src/nsNntpService.cpp
--- a/mail/components/nsMailDefaultHandler.js
+++ b/mail/components/nsMailDefaultHandler.js
@@ -151,18 +151,27 @@ function openURI(uri)
     QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIRequestObserver,
                                            Components.interfaces.nsISupportsWeakReference])
   };
 
   loadgroup.groupObserver = loadlistener;
 
   var listener = {
     onStartURIOpen: function(uri) { return false; },
-    doContent: function(ctype, preferred, request, handler) { return false; },
-    isPreferred: function(ctype, desired) { return false; },
+    doContent: function(ctype, preferred, request, handler) {
+      var newHandler = Components.classes["@mozilla.org/uriloader/content-handler;1?type=application/x-message-display"]
+                                 .createInstance(Components.interfaces.nsIContentHandler);
+      newHandler.handleContent("application/x-message-display", this, request);
+      return true;
+    },
+    isPreferred: function(ctype, desired) {
+      if (ctype == "message/rfc822")
+        return true;
+      return false;
+    },
     canHandleContent: function(ctype, preferred, desired) { return false; },
     loadCookie: null,
     parentContentListener: null,
     getInterface: function(iid) {
       if (iid.equals(Components.interfaces.nsIURIContentListener))
         return this;
 
       if (iid.equals(Components.interfaces.nsILoadGroup))
--- a/mailnews/base/util/nsMsgProtocol.cpp
+++ b/mailnews/base/util/nsMsgProtocol.cpp
@@ -550,16 +550,20 @@ nsresult nsMsgProtocol::LoadUrl(nsIURI *
 
         nsCOMPtr<nsIInputStreamPump> pump;
         rv = NS_NewInputStreamPump(getter_AddRefs(pump),
           m_inputStream, -1, m_readCount);
         if (NS_FAILED(rv)) return rv;
 
         m_request = pump; // keep a reference to the pump so we can cancel it
 
+        // This helps when running URLs from the command line
+        rv = pump->SetLoadGroup(m_loadGroup);
+        NS_ENSURE_SUCCESS(rv, rv);
+
         // put us in a state where we are always notified of incoming data
         rv = pump->AsyncRead(this, urlSupports);
         NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncRead failed");
         m_socketIsOpen = PR_TRUE; // mark the channel as open
       }
     } // if we got an event queue service
     else if (!msgIsInLocalCache) // the connection is already open so we should begin processing our new url...
       rv = ProcessProtocolState(aURL, nsnull, 0, 0);
--- a/mailnews/news/src/nsNntpIncomingServer.cpp
+++ b/mailnews/news/src/nsNntpIncomingServer.cpp
@@ -764,16 +764,27 @@ nsNntpIncomingServer::OnStopRunningUrl(n
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNntpIncomingServer::ContainsNewsgroup(const nsACString &name,
                                         bool *containsGroup)
 {
     if (name.IsEmpty()) return NS_ERROR_FAILURE;
+    if (mSubscribedNewsgroups.Length() == 0)
+    {
+      // If this is empty, we may need to discover folders
+      nsCOMPtr<nsIMsgFolder> rootFolder;
+      GetRootFolder(getter_AddRefs(rootFolder));
+      if (rootFolder)
+      {
+        nsCOMPtr<nsISimpleEnumerator> subfolders;
+        rootFolder->GetSubFolders(getter_AddRefs(subfolders));
+      }
+    }
     nsCAutoString unescapedName;
     MsgUnescapeString(name, 0, unescapedName);
     *containsGroup = mSubscribedNewsgroups.Contains(name);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNntpIncomingServer::SubscribeToNewsgroup(const nsACString &aName)
--- a/mailnews/news/src/nsNntpService.cpp
+++ b/mailnews/news/src/nsNntpService.cpp
@@ -80,16 +80,18 @@
 #include "prprf.h"
 #include "nsICacheService.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsMsgUtils.h"
 #include "nsNetUtil.h"
 #include "nsIWindowWatcher.h"
 #include "nsICommandLine.h"
 #include "nsIMsgMailNewsUrl.h"
+#include "nsIMsgMailSession.h"
+#include "nsISupportsPrimitives.h"
 
 #undef GetPort  // XXX Windows!
 #undef SetPort  // XXX Windows!
 
 #define PREF_MAIL_ROOT_NNTP   "mail.root.nntp"        // old - for backward compatibility only
 #define PREF_MAIL_ROOT_NNTP_REL   "mail.root.nntp-rel"
 
 nsNntpService::nsNntpService()
@@ -1040,89 +1042,52 @@ nsNntpService::GetServerForUri(nsIURI *a
 
   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv,rv);
 
   // find the incoming server, it if exists.
   // migrate if necessary, before searching for it.
   // if it doesn't exist, create it.
   nsCOMPtr<nsIMsgIncomingServer> server;
-  nsCOMPtr<nsINntpIncomingServer> nntpServer;
 
-  nsCOMPtr <nsISupportsArray> accounts;
-  rv = accountManager->GetAccounts(getter_AddRefs(accounts));
-  if (NS_FAILED(rv)) return rv;
+  // Grab all servers for if this is a no-authority URL. This also loads
+  // accounts if they haven't been loaded, i.e., we're running this straight
+  // from the command line
+  nsCOMPtr <nsISupportsArray> servers;
+  rv = accountManager->GetAllServers(getter_AddRefs(servers));
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // news:group becomes news://group, so we have three types of urls:
-  // news://group       (autosubscribing without a host)
-  // news://host/group  (autosubscribing with a host)
-  // news://host        (updating the unread message counts on a server)
-  //
-  // first, check if hostName is really a server or a group
-  // by looking for a server with hostName
-  //
-  // xxx todo what if we have two servers on the same host, but different ports?
-  // Or no port, but scheme (snews:// vs news://) is different?
-  rv = accountManager->FindServerByURI(aUri, PR_FALSE,
-                                getter_AddRefs(server));
+  nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(aUri, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!server)
-  {
-    // try the "real" settings ("realservername" and "realusername")
-    rv = accountManager->FindServerByURI(aUri, PR_TRUE,
-                                getter_AddRefs(server));
-  }
+  rv = mailUrl->GetServer(getter_AddRefs(server));
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // if we didn't find the server, and path was "/", this is a news://group url
-  if (!server && !strcmp("/",path.get()))
+  if (!server && !hostName.IsEmpty())
   {
-    // the uri was news://group and we want to turn that into news://host/group
-    // step 1, set the path to be the hostName;
-    rv = aUri->SetPath(hostName);
-    NS_ENSURE_SUCCESS(rv,rv);
-
-    // until we support default news servers, use the first nntp server we find
-    rv = accountManager->FindServerByURI(aUri, PR_FALSE, getter_AddRefs(server));
-    if (NS_FAILED(rv) || !server)
-    {
-        // step 2, set the uri's hostName and the local variable hostName
-        // to be "news"
-        rv = aUri->SetHost(NS_LITERAL_CSTRING("news"));
-        NS_ENSURE_SUCCESS(rv,rv);
-
-        rv = aUri->GetAsciiHost(hostName);
-        NS_ENSURE_SUCCESS(rv,rv);
-    }
-    else
-    {
-        // step 2, set the uri's hostName and the local variable hostName
-        // to be the host name of the server we found
-        rv = server->GetHostName(hostName);
-        NS_ENSURE_SUCCESS(rv,rv);
-
-        rv = aUri->SetHost(hostName);
-        NS_ENSURE_SUCCESS(rv,rv);
-    }
-  }
-
-  if (NS_FAILED(rv) || !server)
-  {
+    // If we don't have this server but it isn't no-auth, add it.
+    // Ideally, we should remove this account quickly (see bug 41133)
     bool useSSL = false;
-    if (PL_strcasecmp("snews", scheme.get()) == 0)
+    if (scheme.EqualsLiteral("snews") || scheme.EqualsLiteral("nntps"))
     {
       useSSL = PR_TRUE;
       if ((port == 0) || (port == -1))
           port = nsINntpUrl::DEFAULT_NNTPS_PORT;
     }
     rv = CreateNewsAccount(hostName.get(), useSSL, port, getter_AddRefs(server));
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  if (NS_FAILED(rv)) return rv;
+  if (!server && hostName.IsEmpty())
+    // XXX: Until we support no-auth uris, bail
+    return NS_ERROR_FAILURE;
+
   if (!server) return NS_ERROR_FAILURE;
 
+  nsCOMPtr<nsINntpIncomingServer> nntpServer;
   nntpServer = do_QueryInterface(server, &rv);
 
   if (!nntpServer || NS_FAILED(rv))
     return rv;
 
   NS_IF_ADDREF(*aServer = nntpServer);
 
   nsCAutoString spec;
@@ -1743,52 +1708,68 @@ nsNntpService::HandleContent(const char 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // check for x-application-newsgroup or x-application-newsgroup-listids
   if (PL_strncasecmp(aContentType, "x-application-newsgroup", 23) == 0)
   {
     nsCOMPtr<nsIURI> uri;
     rv = aChannel->GetURI(getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
-    if (uri)
+
+    nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(uri);
+    if (mailUrl)
     {
-      nsCString uriStr;
-      rv = uri->GetSpec(uriStr);
+      nsCOMPtr<nsIMsgFolder> msgFolder;
+      rv = mailUrl->GetFolder(getter_AddRefs(msgFolder));
       NS_ENSURE_SUCCESS(rv, rv);
 
-      PRInt32 cutChar = uriStr.FindChar('?');
-      if (cutChar > 0)
-        uriStr.SetLength(cutChar);
+      // No folder means we can't handle this
+      if (!msgFolder)
+        return NS_ERROR_WONT_HANDLE_CONTENT;
 
-      // Try to get a valid folder...
-      nsCOMPtr <nsIMsgFolder> msgFolder;
-      GetFolderFromUri(uriStr.get(), getter_AddRefs(msgFolder));
-
-      // ... and only go on if we have a valid URI (i.e., valid folder)
-      if (msgFolder)
+      nsCString folderURL;
+      rv = msgFolder->GetURI(folderURL);
+      NS_ENSURE_SUCCESS(rv, rv);
+      
+      nsCOMPtr<nsIMsgWindow> msgWindow;
+      mailUrl->GetMsgWindow(getter_AddRefs(msgWindow));
+      if (!msgWindow)
       {
-        nsCOMPtr <nsIURI> originalUri;
-        aChannel->GetOriginalURI(getter_AddRefs(originalUri));
-        if (originalUri)
+        // This came from a docshell that didn't set msgWindow, so find one
+        nsCOMPtr<nsIMsgMailSession> mailSession =
+          do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
+
+        if (!msgWindow)
         {
-          nsCOMPtr <nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(originalUri);
-          if (mailUrl)
-          {
-            nsCOMPtr <nsIMsgWindow> msgWindow;
-            mailUrl->GetMsgWindow(getter_AddRefs(msgWindow));
-            if (msgWindow)
-            {
-              nsCOMPtr <nsIMsgWindowCommands> windowCommands;
-              msgWindow->GetWindowCommands(getter_AddRefs(windowCommands));
-              if (windowCommands)
-                windowCommands->SelectFolder(uriStr);
-            }
-          }
+          // We need to create a 3-pane window, then
+          nsCOMPtr<nsIWindowWatcher> wwatcher =
+            do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
+          NS_ENSURE_SUCCESS(rv, rv);
+
+          nsCOMPtr<nsISupportsCString> arg =
+            do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
+          arg->SetData(folderURL);
+
+          nsCOMPtr<nsIDOMWindow> newWindow;
+          rv = wwatcher->OpenWindow(nsnull, "chrome://messenger/content/",
+            "_blank", "chome,all,dialog=no", arg, getter_AddRefs(newWindow));
+          NS_ENSURE_SUCCESS(rv, rv);
         }
       }
+      if (msgWindow)
+      {
+        nsCOMPtr<nsIMsgWindowCommands> windowCommands;
+        msgWindow->GetWindowCommands(getter_AddRefs(windowCommands));
+        if (windowCommands)
+          windowCommands->SelectFolder(folderURL);
+      }
+      request->Cancel(NS_BINDING_ABORTED);
     }
   } else // The content-type was not x-application-newsgroup.
     rv = NS_ERROR_WONT_HANDLE_CONTENT;
   return rv;
 }
 
 NS_IMETHODIMP
 nsNntpService::MessageURIToMsgHdr(const char *uri, nsIMsgDBHdr **_retval)