Bug 390721 - When parsing headers to cancel an article, also use folded lines. r=jorgk
authorAlfred Peters <infofrommozilla@gmail.com>
Sun, 02 Dec 2018 08:59:00 +0100
changeset 33845 7cdd9ac6221e517b841c4cb786f05bad32576e0c
parent 33844 894ad5c9dce3f0dd09735f0cf5f0b98d62fe02ea
child 33846 b0cfc39adb1ed781b9f8975869517e35f35811de
push id388
push userclokep@gmail.com
push dateMon, 28 Jan 2019 20:54:56 +0000
reviewersjorgk
bugs390721
Bug 390721 - When parsing headers to cancel an article, also use folded lines. r=jorgk
mailnews/news/src/nsNNTPProtocol.cpp
mailnews/news/src/nsNNTPProtocol.h
--- a/mailnews/news/src/nsNNTPProtocol.cpp
+++ b/mailnews/news/src/nsNNTPProtocol.cpp
@@ -259,21 +259,16 @@ nsNNTPProtocol::nsNNTPProtocol(nsINntpIn
 : nsMsgProtocol(aURL),
   m_connectionBusy(false),
   m_nntpServer(aServer)
 {
   m_ProxyServer = nullptr;
   m_responseText = nullptr;
   m_dataBuf = nullptr;
 
-  m_cancelFromHdr = nullptr;
-  m_cancelNewsgroups = nullptr;
-  m_cancelDistribution = nullptr;
-  m_cancelID = nullptr;
-
   m_key = nsMsgKey_None;
 
   mBytesReceived = 0;
   mBytesReceivedSinceLastStatusUpdate = 0;
   m_startTime = PR_Now();
 
   if (aMsgWindow) {
     m_msgWindow = aMsgWindow;
@@ -300,20 +295,16 @@ nsNNTPProtocol::~nsNNTPProtocol()
   }
   Cleanup();
 }
 
 void nsNNTPProtocol::Cleanup()  //free char* member variables
 {
   PR_FREEIF(m_responseText);
   PR_FREEIF(m_dataBuf);
-  PR_FREEIF(m_cancelFromHdr);
-  PR_FREEIF(m_cancelNewsgroups);
-  PR_FREEIF(m_cancelDistribution);
-  PR_FREEIF(m_cancelID);
 }
 
 NS_IMETHODIMP nsNNTPProtocol::Initialize(nsIURI *aURL, nsIMsgWindow *aMsgWindow)
 {
   if (aMsgWindow) {
     m_msgWindow = aMsgWindow;
   }
   nsMsgProtocol::InitFromURI(aURL);
@@ -424,20 +415,20 @@ NS_IMETHODIMP nsNNTPProtocol::Initialize
   m_lastPossibleArticle = 0;
   m_numArticlesLoaded = 0;
   m_numArticlesWanted = 0;
 
   m_key = nsMsgKey_None;
 
   m_articleNumber = 0;
   m_originalContentLength = 0;
-  m_cancelID = nullptr;
-  m_cancelFromHdr = nullptr;
-  m_cancelNewsgroups = nullptr;
-  m_cancelDistribution = nullptr;
+  m_cancelID.Truncate();
+  m_cancelFromHdr.Truncate();
+  m_cancelNewsgroups.Truncate();
+  m_cancelDistribution.Truncate();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsNNTPProtocol::GetIsBusy(bool *aIsBusy)
 {
   NS_ENSURE_ARG_POINTER(aIsBusy);
   *aIsBusy = m_connectionBusy;
   return NS_OK;
@@ -2252,47 +2243,70 @@ nsresult nsNNTPProtocol::ReadArticle(nsI
 
   PR_Free(line);
 
   return NS_OK;
 }
 
 void nsNNTPProtocol::ParseHeaderForCancel(char *buf)
 {
+    static int lastHeader = 0;
     nsAutoCString header(buf);
+    if (header.First() == ' ' || header.First() == '\t') {
+        header.StripWhitespace();
+        // Add folded line to header if needed.
+        switch (lastHeader) {
+        case 1:
+            m_cancelFromHdr += header;
+            break;
+        case 2:
+            m_cancelID += header;
+            break;
+        case 3:
+            m_cancelNewsgroups += header;
+            break;
+        case 4:
+            m_cancelDistribution += header;
+            break;
+        }
+        // Other folded lines are of no interest.
+        return;
+    }
+
+    lastHeader = 0;
     int32_t colon = header.FindChar(':');
     if (!colon)
     return;
 
     nsCString value(Substring(header, colon + 1));
     value.StripWhitespace();
 
     switch (header.First()) {
     case 'F': case 'f':
         if (header.Find("From", /* ignoreCase = */ true) == 0) {
-            PR_FREEIF(m_cancelFromHdr);
-      m_cancelFromHdr = ToNewCString(value);
+            m_cancelFromHdr = value;
+            lastHeader = 1;
         }
         break;
     case 'M': case 'm':
         if (header.Find("Message-ID", /* ignoreCase = */ true) == 0) {
-            PR_FREEIF(m_cancelID);
-      m_cancelID = ToNewCString(value);
+            m_cancelID = value;
+            lastHeader = 2;
         }
         break;
     case 'N': case 'n':
         if (header.Find("Newsgroups", /* ignoreCase = */ true) == 0) {
-            PR_FREEIF(m_cancelNewsgroups);
-      m_cancelNewsgroups = ToNewCString(value);
+            m_cancelNewsgroups = value;
+            lastHeader = 3;
         }
         break;
      case 'D': case 'd':
         if (header.Find("Distributions", /* ignoreCase = */ true) == 0) {
-            PR_FREEIF(m_cancelDistribution);
-      m_cancelDistribution = ToNewCString(value);
+            m_cancelDistribution = value;
+            lastHeader = 4;
         }
         break;
     }
 
   return;
 }
 
 nsresult nsNNTPProtocol::BeginAuthorization()
@@ -3534,82 +3548,63 @@ void nsNNTPProtocol::CheckIfAuthor(nsIMs
     aFrom = from;
 }
 
 nsresult nsNNTPProtocol::DoCancel()
 {
     int32_t status = 0;
     bool failure = false;
     nsresult rv = NS_OK;
-    char *id = nullptr;
-    char *subject = nullptr;
-    char *newsgroups = nullptr;
-    char *distribution = nullptr;
-    char *body = nullptr;
     bool requireConfirmationForCancel = true;
     bool showAlertAfterCancel = true;
 
-    int L;
-
   /* #### Should we do a more real check than this?  If the POST command
      didn't respond with "MK_NNTP_RESPONSE_POST_SEND_NOW Ok", then it's not ready for us to throw a
      message at it...   But the normal posting code doesn't do this check.
      Why?
    */
   NS_ASSERTION (m_responseCode == MK_NNTP_RESPONSE_POST_SEND_NOW, "code != POST_SEND_NOW");
 
-  // These shouldn't be set yet, since the headers haven't been "flushed"
-  // "Distribution: " doesn't appear to be required, so
-  // don't assert on m_cancelDistribution
-  NS_ASSERTION (m_cancelID &&
-   m_cancelFromHdr &&
-   m_cancelNewsgroups, "null ptr");
-
   nsCOMPtr<nsIStringBundleService> bundleService =
     mozilla::services::GetStringBundleService();
   NS_ENSURE_TRUE(bundleService, NS_ERROR_OUT_OF_MEMORY);
 
   nsCOMPtr<nsIStringBundle> brandBundle;
   bundleService->CreateBundle("chrome://branding/locale/brand.properties",
                               getter_AddRefs(brandBundle));
   NS_ENSURE_TRUE(brandBundle, NS_ERROR_FAILURE);
 
   nsString brandFullName;
   rv = brandBundle->GetStringFromName("brandFullName", brandFullName);
   NS_ENSURE_SUCCESS(rv,rv);
   NS_ConvertUTF16toUTF8 appName(brandFullName);
 
-  newsgroups = m_cancelNewsgroups;
-  distribution = m_cancelDistribution;
-  id = m_cancelID;
+  nsCString newsgroups(m_cancelNewsgroups);
+  nsCString distribution (m_cancelDistribution);
+  nsCString id (m_cancelID);
   nsCString oldFrom(m_cancelFromHdr);
 
   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv,rv);
 
   nsCOMPtr<nsIPrompt> dialog;
   if (m_runningURL)
   {
     nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(m_runningURL));
     rv = GetPromptDialogFromUrl(msgUrl, getter_AddRefs(dialog));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  NS_ASSERTION (id && newsgroups, "null ptr");
-  if (!id || !newsgroups) return NS_ERROR_FAILURE;
-
-  m_cancelNewsgroups = nullptr;
-  m_cancelDistribution = nullptr;
-  m_cancelFromHdr = nullptr;
-  m_cancelID = nullptr;
-
-  L = PL_strlen (id);
-
-  subject = (char *) PR_Malloc (L + 20);
-  body = (char *) PR_Malloc (PL_strlen (appName.get()) + 100);
+  if (id.IsEmpty() || newsgroups.IsEmpty())
+    return NS_ERROR_FAILURE;
+
+  m_cancelNewsgroups.Truncate();
+  m_cancelDistribution.Truncate();
+  m_cancelFromHdr.Truncate();
+  m_cancelID.Truncate();
 
   nsString alertText;
   nsString confirmText;
   int32_t confirmCancelResult = 0;
 
   // A little early to declare, but the goto causes problems
   nsAutoCString otherHeaders;
 
@@ -3687,59 +3682,45 @@ nsresult nsNNTPProtocol::DoCancel()
 
   if (confirmCancelResult != 0) {
       // they cancelled the cancel
       status = MK_NNTP_NOT_CANCELLED;
       failure = true;
       goto FAIL;
   }
 
-  if (!subject || !body)
-  {
-    status = MK_OUT_OF_MEMORY;
-    failure = true;
-    goto FAIL;
-  }
-
-  PL_strcpy (subject, "cancel ");
-  PL_strcat (subject, id);
-
   otherHeaders.AppendLiteral("Control: cancel ");
   otherHeaders += id;
   otherHeaders.AppendLiteral(CRLF);
-  if (distribution) {
+  if (!distribution.IsEmpty()) {
     otherHeaders.AppendLiteral("Distribution: ");
     otherHeaders += distribution;
     otherHeaders.AppendLiteral(CRLF);
   }
   otherHeaders.AppendLiteral("MIME-Version: 1.0");
   otherHeaders.AppendLiteral(CRLF);
   otherHeaders.AppendLiteral("Content-Type: text/plain");
   otherHeaders.AppendLiteral(CRLF);
 
-  PL_strcpy (body, "This message was cancelled from within ");
-  PL_strcat (body, appName.get());
-  PL_strcat (body, "." CRLF);
-
   m_cancelStatus = 0;
 
   {
     /* NET_BlockingWrite() should go away soon? I think. */
     /* The following are what we really need to cancel a posted message */
     char *data;
     data = PR_smprintf("From: %s" CRLF
                        "Newsgroups: %s" CRLF
-                       "Subject: %s" CRLF
+                       "Subject: cancel %s" CRLF
                        "References: %s" CRLF
                        "%s" /* otherHeaders, already with CRLF */
                        CRLF /* body separator */
-                       "%s" /* body, already with CRLF */
+                       "This message was cancelled from within %s." CRLF /* body */
                        "." CRLF, /* trailing message terminator "." */
-                       from.get(), newsgroups, subject, id,
-                       otherHeaders.get(), body);
+                       from.get(), newsgroups.get(), id.get(), id.get(),
+                       otherHeaders.get(), appName.get());
 
     rv = SendData(data);
     PR_Free (data);
     if (NS_FAILED(rv)) {
       nsAutoCString errorText;
       errorText.AppendInt(status);
       AlertError(MK_TCP_WRITE_ERROR, errorText.get());
       failure = true;
@@ -3768,22 +3749,16 @@ nsresult nsNNTPProtocol::DoCancel()
   }
 
 FAIL:
   NS_ASSERTION(m_newsFolder,"no news folder");
   if (m_newsFolder)
     rv = ( failure ) ? m_newsFolder->CancelFailed()
                      : m_newsFolder->CancelComplete();
 
-  PR_Free (id);
-  PR_Free (subject);
-  PR_Free (newsgroups);
-  PR_Free (distribution);
-  PR_Free (body);
-
   return rv;
 }
 
 nsresult nsNNTPProtocol::XPATSend()
 {
   nsresult rv = NS_OK;
   int32_t slash = m_searchData.FindChar('/');
 
--- a/mailnews/news/src/nsNNTPProtocol.h
+++ b/mailnews/news/src/nsNNTPProtocol.h
@@ -232,21 +232,20 @@ private:
   int32_t   m_lastPossibleArticle;
 
   int32_t    m_numArticlesLoaded;  /* How many articles we got XOVER lines for. */
   int32_t    m_numArticlesWanted; /* How many articles we wanted to get XOVER lines for. */
   int32_t   m_maxArticles;        /* max articles to get during an XOVER */
 
   // Cancelation specific state. In particular, the headers that should be
   // used for the cancelation message.
-  // mscott: we can probably replace this stuff with nsString
-  char   *m_cancelFromHdr;
-  char     *m_cancelNewsgroups;
-  char     *m_cancelDistribution;
-  char     *m_cancelID;
+  nsCString m_cancelFromHdr;
+  nsCString m_cancelNewsgroups;
+  nsCString m_cancelDistribution;
+  nsCString m_cancelID;
   int32_t    m_cancelStatus;
 
   // variable for ReadNewsList
   int32_t   m_readNewsListCount;
 
   // Per news article state information. (article number, author, subject, id, etc
   nsCString m_messageID;
   int32_t   m_articleNumber;   /* current article number */