Bug 1558595 - Improve S/MIME status display. r=mkmelin
authorKai Engert <kaie@kuix.de>
Mon, 24 Jun 2019 11:48:03 +0200
changeset 35943 75c5d68a9a21fd977c743cdd1561dc8735f22660
parent 35942 cf23f4f4e5abfd5d3a97382cb76754e767553bdd
child 35944 ccd0d7d9d7e5607ea870babbd815d7aebda84e4c
push id392
push userclokep@gmail.com
push dateMon, 02 Sep 2019 20:17:19 +0000
reviewersmkmelin
bugs1558595
Bug 1558595 - Improve S/MIME status display. r=mkmelin
mail/extensions/smime/content/msgHdrViewSMIMEOverlay.js
mailnews/extensions/smime/public/nsIMsgSMIMEHeaderSink.idl
mailnews/mime/src/mimecms.cpp
mailnews/mime/src/mimemcms.cpp
--- a/mail/extensions/smime/content/msgHdrViewSMIMEOverlay.js
+++ b/mail/extensions/smime/content/msgHdrViewSMIMEOverlay.js
@@ -28,21 +28,41 @@ function neckoURLForMessageURI(aMessageU
   return neckoURI.value.spec;
 }
 
 var smimeHeaderSink = {
   maxWantedNesting() {
     return 1;
   },
 
-  signedStatus(aNestingLevel, aSignatureStatus, aSignerCert) {
+  isStatusForSelectedMessage(aMsgNeckoURL) {
+    if (!gFolderDisplay.selectedMessage.folder) {
+      // The folder should be absent only if the message gets opened
+      // from an external file (.eml), which is opened in its own window.
+      // That window won't get reused for other messages. We conclude
+      // the incoming status is for this window.
+      // This special handling is necessary, because the necko URL for
+      // separate windows that is seen by the MIME code differs from the
+      // one we see here in JS.
+      return true;
+    }
+
+    let neckoURI = neckoURLForMessageURI(gFolderDisplay.selectedMessageUris[0]);
+    return (neckoURI === aMsgNeckoURL);
+  },
+
+  signedStatus(aNestingLevel, aSignatureStatus, aSignerCert,
+               aMsgNeckoURL) {
     if (aNestingLevel > 1) {
       // we are not interested
       return;
     }
+    if (!this.isStatusForSelectedMessage(aMsgNeckoURL)) {
+      return;
+    }
 
     gSignatureStatus = aSignatureStatus;
     gSignerCert = aSignerCert;
 
     gSMIMEContainer.collapsed = false;
     gSignedUINode.collapsed = false;
 
     switch (aSignatureStatus) {
@@ -94,21 +114,25 @@ var smimeHeaderSink = {
 
     let senderInfo = { name: "sender", outputFunction: OutputEmailAddresses };
     let senderEntry = new createHeaderEntry("expanded", senderInfo);
 
     gExpandedHeaderView[senderInfo.name] = senderEntry;
     UpdateExpandedMessageHeaders();
   },
 
-  encryptionStatus(aNestingLevel, aEncryptionStatus, aRecipientCert) {
+  encryptionStatus(aNestingLevel, aEncryptionStatus, aRecipientCert,
+                   aMsgNeckoURL) {
     if (aNestingLevel > 1) {
       // we are not interested
       return;
     }
+    if (!this.isStatusForSelectedMessage(aMsgNeckoURL)) {
+      return;
+    }
 
     gEncryptionStatus = aEncryptionStatus;
     gEncryptionCert = aRecipientCert;
 
     gSMIMEContainer.collapsed = false;
     gEncryptedUINode.collapsed = false;
 
     if (Ci.nsICMSMessageErrors.SUCCESS == aEncryptionStatus) {
--- a/mailnews/extensions/smime/public/nsIMsgSMIMEHeaderSink.idl
+++ b/mailnews/extensions/smime/public/nsIMsgSMIMEHeaderSink.idl
@@ -11,13 +11,19 @@
 
 #include "nsISupports.idl"
 
 interface nsIX509Cert;
 
 [scriptable, uuid(25380FA1-E70C-4e82-B0BC-F31C2F41C470)]
 interface nsIMsgSMIMEHeaderSink : nsISupports
 {
-  void signedStatus(in long aNestingLevel, in long aSignatureStatus, in nsIX509Cert aSignerCert);
-  void encryptionStatus(in long aNestingLevel, in long aEncryptionStatus, in nsIX509Cert aReceipientCert);
+  void signedStatus(in long aNestingLevel,
+                    in long aSignatureStatus,
+                    in nsIX509Cert aSignerCert,
+                    in AUTF8String aMsgNeckoURL);
+  void encryptionStatus(in long aNestingLevel,
+                        in long aEncryptionStatus,
+                        in nsIX509Cert aReceipientCert,
+                        in AUTF8String aMsgNeckoURL);
 
   long maxWantedNesting(); // 1 == only info on outermost nesting level wanted
 };
--- a/mailnews/mime/src/mimecms.cpp
+++ b/mailnews/mime/src/mimecms.cpp
@@ -66,16 +66,17 @@ typedef struct MimeCMSdata {
   bool ci_is_encrypted;
   char *sender_addr;
   bool decoding_failed;
   uint32_t decoded_bytes;
   MimeObject *self;
   bool parent_is_encrypted_p;
   bool parent_holds_stamp_p;
   nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
+  nsCString url;
 
   MimeCMSdata()
       : output_fn(nullptr),
         output_closure(nullptr),
         ci_is_encrypted(false),
         sender_addr(nullptr),
         decoding_failed(false),
         decoded_bytes(0),
@@ -185,17 +186,18 @@ bool MimeCMSHeadersAndCertsMatch(nsICMSM
 class nsSMimeVerificationListener : public nsISMimeVerificationListener {
  public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSISMIMEVERIFICATIONLISTENER
 
   nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName,
                               const char *aSenderAddr, const char *aSenderName,
                               nsIMsgSMIMEHeaderSink *aHeaderSink,
-                              int32_t aMimeNestingLevel);
+                              int32_t aMimeNestingLevel,
+                              const nsCString &aMsgNeckoURL);
 
  protected:
   virtual ~nsSMimeVerificationListener() {}
 
   /**
    * It is safe to declare this implementation as thread safe,
    * despite not using a lock to protect the members.
    * Because of the way the object will be used, we don't expect a race.
@@ -205,70 +207,77 @@ class nsSMimeVerificationListener : publ
    * When the other thread is finished, it will call into the "Notify"
    * callback. Self's members will be accessed on the other thread,
    * but this is fine, because there is no race with the original thread.
    * Race-protection for XPCOM reference counting is sufficient.
    */
   bool mSinkIsNull;
   nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> mHeaderSink;
   int32_t mMimeNestingLevel;
+  nsCString mMsgNeckoURL;
 
   nsCString mFromAddr;
   nsCString mFromName;
   nsCString mSenderAddr;
   nsCString mSenderName;
 };
 
 class SignedStatusRunnable : public mozilla::Runnable {
  public:
   SignedStatusRunnable(
       const nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> &aSink,
       int32_t aNestingLevel, int32_t aSignatureStatus,
-      nsIX509Cert *aSignerCert);
+      nsIX509Cert *aSignerCert, const nsCString &aMsgNeckoURL);
   NS_DECL_NSIRUNNABLE
   nsresult mResult;
 
  protected:
   nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> m_sink;
   int32_t m_nestingLevel;
   int32_t m_signatureStatus;
   nsCOMPtr<nsIX509Cert> m_signerCert;
+  nsCString m_msgNeckoURL;
 };
 
 SignedStatusRunnable::SignedStatusRunnable(
     const nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> &aSink,
-    int32_t aNestingLevel, int32_t aSignatureStatus, nsIX509Cert *aSignerCert)
+    int32_t aNestingLevel, int32_t aSignatureStatus, nsIX509Cert *aSignerCert,
+    const nsCString &aMsgNeckoURL)
     : mozilla::Runnable("SignedStatusRunnable"),
       m_sink(aSink),
       m_nestingLevel(aNestingLevel),
       m_signatureStatus(aSignatureStatus),
-      m_signerCert(aSignerCert) {}
+      m_signerCert(aSignerCert),
+      m_msgNeckoURL(aMsgNeckoURL) {}
 
 NS_IMETHODIMP SignedStatusRunnable::Run() {
   mResult =
-      m_sink->SignedStatus(m_nestingLevel, m_signatureStatus, m_signerCert);
+      m_sink->SignedStatus(m_nestingLevel, m_signatureStatus, m_signerCert,
+                           m_msgNeckoURL);
   return NS_OK;
 }
 
 nsresult ProxySignedStatus(
     const nsMainThreadPtrHandle<nsIMsgSMIMEHeaderSink> &aSink,
-    int32_t aNestingLevel, int32_t aSignatureStatus, nsIX509Cert *aSignerCert) {
+    int32_t aNestingLevel, int32_t aSignatureStatus, nsIX509Cert *aSignerCert,
+    const nsCString &aMsgNeckoURL) {
   RefPtr<SignedStatusRunnable> signedStatus = new SignedStatusRunnable(
-      aSink, aNestingLevel, aSignatureStatus, aSignerCert);
+      aSink, aNestingLevel, aSignatureStatus, aSignerCert, aMsgNeckoURL);
   nsresult rv = NS_DispatchToMainThread(signedStatus, NS_DISPATCH_SYNC);
   NS_ENSURE_SUCCESS(rv, rv);
   return signedStatus->mResult;
 }
 
 NS_IMPL_ISUPPORTS(nsSMimeVerificationListener, nsISMimeVerificationListener)
 
 nsSMimeVerificationListener::nsSMimeVerificationListener(
     const char *aFromAddr, const char *aFromName, const char *aSenderAddr,
     const char *aSenderName, nsIMsgSMIMEHeaderSink *aHeaderSink,
-    int32_t aMimeNestingLevel) {
+    int32_t aMimeNestingLevel, const nsCString &aMsgNeckoURL)
+    : mMsgNeckoURL(aMsgNeckoURL) {
   mHeaderSink = new nsMainThreadPtrHolder<nsIMsgSMIMEHeaderSink>(
       "nsSMimeVerificationListener::mHeaderSink", aHeaderSink);
   mSinkIsNull = !aHeaderSink;
   mMimeNestingLevel = aMimeNestingLevel;
 
   mFromAddr = aFromAddr;
   mFromName = aFromName;
   mSenderAddr = aSenderAddr;
@@ -305,17 +314,17 @@ NS_IMETHODIMP nsSMimeVerificationListene
         signature_status = nsICMSMessageErrors::VERIFY_CERT_WITHOUT_ADDRESS;
       else
         signature_status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH;
     } else
       signature_status = nsICMSMessageErrors::SUCCESS;
   }
 
   ProxySignedStatus(mHeaderSink, mMimeNestingLevel, signature_status,
-                    signerCert);
+                    signerCert, mMsgNeckoURL);
 
   return NS_OK;
 }
 
 int MIMEGetRelativeCryptoNestLevel(MimeObject *obj) {
   /*
     the part id of any mimeobj is mime_part_address(obj)
     our currently displayed crypto part is obj
@@ -436,35 +445,34 @@ static void *MimeCMS_init(MimeObject *ob
     if (channel) {
       nsCOMPtr<nsIURI> uri;
       nsCOMPtr<nsIMsgWindow> msgWindow;
       nsCOMPtr<nsIMsgHeaderSink> headerSink;
       nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
       nsCOMPtr<nsISupports> securityInfo;
       channel->GetURI(getter_AddRefs(uri));
       if (uri) {
-        nsAutoCString urlSpec;
-        rv = uri->GetSpec(urlSpec);
+        rv = uri->GetSpec(data->url);
 
         // We only want to update the UI if the current mime transaction
         // is intended for display.
         // If the current transaction is intended for background processing,
         // we can learn that by looking at the additional header=filter
         // string contained in the URI.
         //
         // If we find something, we do not set smimeHeaderSink,
         // which will prevent us from giving UI feedback.
         //
         // If we do not find header=filter, we assume the result of the
         // processing will be shown in the UI.
 
-        if (!strstr(urlSpec.get(), "?header=filter") &&
-            !strstr(urlSpec.get(), "&header=filter") &&
-            !strstr(urlSpec.get(), "?header=attach") &&
-            !strstr(urlSpec.get(), "&header=attach")) {
+        if (!strstr(data->url.get(), "?header=filter") &&
+            !strstr(data->url.get(), "&header=filter") &&
+            !strstr(data->url.get(), "?header=attach") &&
+            !strstr(data->url.get(), "&header=attach")) {
           msgurl = do_QueryInterface(uri);
           if (msgurl) msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
           if (msgWindow)
             msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
           if (headerSink)
             headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
           if (securityInfo)
             data->smimeHeaderSink = do_QueryInterface(securityInfo);
@@ -519,21 +527,22 @@ void MimeCMSGetFromSender(MimeObject *ob
   if (!s.IsEmpty())
     ExtractFirstAddress(EncodedHeader(s), sender_name, sender_addr);
 }
 
 void MimeCMSRequestAsyncSignatureVerification(
     nsICMSMessage *aCMSMsg, const char *aFromAddr, const char *aFromName,
     const char *aSenderAddr, const char *aSenderName,
     nsIMsgSMIMEHeaderSink *aHeaderSink, int32_t aMimeNestingLevel,
+    const nsCString &aMsgNeckoURL,
     unsigned char *item_data, uint32_t item_len, int16_t digest_type) {
   RefPtr<nsSMimeVerificationListener> listener =
       new nsSMimeVerificationListener(aFromAddr, aFromName, aSenderAddr,
                                       aSenderName, aHeaderSink,
-                                      aMimeNestingLevel);
+                                      aMimeNestingLevel, aMsgNeckoURL);
   if (item_data)
     aCMSMsg->AsyncVerifyDetachedSignature(listener, item_data, item_len,
                                           digest_type);
   else
     aCMSMsg->AsyncVerifySignature(listener);
 }
 
 static int MimeCMS_eof(void *crypto_closure, bool abort_p) {
@@ -614,23 +623,23 @@ static int MimeCMS_eof(void *crypto_clos
       nsCString sender_name;
 
       MimeCMSGetFromSender(data->self, from_addr, from_name, sender_addr,
                            sender_name);
 
       MimeCMSRequestAsyncSignatureVerification(
           data->content_info, from_addr.get(), from_name.get(),
           sender_addr.get(), sender_name.get(), data->smimeHeaderSink,
-          aRelativeNestLevel, nullptr, 0, 0);
+          aRelativeNestLevel, data->url, nullptr, 0, 0);
     }
   }
 
   if (data->ci_is_encrypted) {
     data->smimeHeaderSink->EncryptionStatus(aRelativeNestLevel, status,
-                                            certOfInterest);
+                                            certOfInterest, data->url);
   }
 
   return 0;
 }
 
 static void MimeCMS_free(void *crypto_closure) {
   MimeCMSdata *data = (MimeCMSdata *)crypto_closure;
   if (!data) return;
--- a/mailnews/mime/src/mimemcms.cpp
+++ b/mailnews/mime/src/mimemcms.cpp
@@ -73,16 +73,17 @@ typedef struct MimeMultCMSdata {
   char *sender_addr;
   bool decoding_failed;
   unsigned char *item_data;
   uint32_t item_len;
   MimeObject *self;
   bool parent_is_encrypted_p;
   bool parent_holds_stamp_p;
   nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
+  nsCString url;
 
   MimeMultCMSdata()
       : hash_type(0),
         sender_addr(nullptr),
         decoding_failed(false),
         item_data(nullptr),
         self(nullptr),
         parent_is_encrypted_p(false),
@@ -108,16 +109,17 @@ extern void MimeCMSGetFromSender(MimeObj
                                  nsCString &from_name, nsCString &sender_addr,
                                  nsCString &sender_name);
 extern bool MimeCMSHeadersAndCertsMatch(
     MimeObject *obj, nsICMSMessage *, bool *signing_cert_without_email_address);
 extern void MimeCMSRequestAsyncSignatureVerification(
     nsICMSMessage *aCMSMsg, const char *aFromAddr, const char *aFromName,
     const char *aSenderAddr, const char *aSenderName,
     nsIMsgSMIMEHeaderSink *aHeaderSink, int32_t aMimeNestingLevel,
+    const nsCString &aMsgNeckoURL,
     unsigned char *item_data, uint32_t item_len, int16_t digest_type);
 extern char *MimeCMS_MakeSAURL(MimeObject *obj);
 extern char *IMAP_CreateReloadAllPartsUrl(const char *url);
 extern int MIMEGetRelativeCryptoNestLevel(MimeObject *obj);
 
 static void *MimeMultCMS_init(MimeObject *obj) {
   MimeHeaders *hdrs = obj->headers;
   MimeMultCMSdata *data = 0;
@@ -203,35 +205,34 @@ static void *MimeMultCMS_init(MimeObject
     if (channel) {
       nsCOMPtr<nsIURI> uri;
       nsCOMPtr<nsIMsgWindow> msgWindow;
       nsCOMPtr<nsIMsgHeaderSink> headerSink;
       nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
       nsCOMPtr<nsISupports> securityInfo;
       channel->GetURI(getter_AddRefs(uri));
       if (uri) {
-        nsAutoCString urlSpec;
-        rv = uri->GetSpec(urlSpec);
+        rv = uri->GetSpec(data->url);
 
         // We only want to update the UI if the current mime transaction
         // is intended for display.
         // If the current transaction is intended for background processing,
         // we can learn that by looking at the additional header=filter
         // string contained in the URI.
         //
         // If we find something, we do not set smimeHeaderSink,
         // which will prevent us from giving UI feedback.
         //
         // If we do not find header=filter, we assume the result of the
         // processing will be shown in the UI.
 
-        if (!strstr(urlSpec.get(), "?header=filter") &&
-            !strstr(urlSpec.get(), "&header=filter") &&
-            !strstr(urlSpec.get(), "?header=attach") &&
-            !strstr(urlSpec.get(), "&header=attach")) {
+        if (!strstr(data->url.get(), "?header=filter") &&
+            !strstr(data->url.get(), "&header=filter") &&
+            !strstr(data->url.get(), "?header=attach") &&
+            !strstr(data->url.get(), "&header=attach")) {
           msgurl = do_QueryInterface(uri);
           if (msgurl) msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
           if (msgWindow)
             msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
           if (headerSink)
             headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
           if (securityInfo)
             data->smimeHeaderSink = do_QueryInterface(securityInfo);
@@ -377,20 +378,21 @@ static char *MimeMultCMS_generate(void *
 
     if (aRelativeNestLevel > maxNestLevel) return nullptr;
   }
 
   if (data->self->options->missing_parts) {
     // We were not given all parts of the message.
     // We are therefore unable to verify correctness of the signature.
 
-    if (data->smimeHeaderSink)
+    if (data->smimeHeaderSink) {
       data->smimeHeaderSink->SignedStatus(
           aRelativeNestLevel, nsICMSMessageErrors::VERIFY_NOT_YET_ATTEMPTED,
-          nullptr);
+          nullptr, data->url);
+    }
     return nullptr;
   }
 
   if (!data->content_info) {
     /* No content_info at all -- since we're inside a multipart/signed,
      that means that we've either gotten a message that was truncated
      before the signature part, or we ran out of memory, or something
      awful has happened.
@@ -404,17 +406,17 @@ static char *MimeMultCMS_generate(void *
   nsCString sender_name;
 
   MimeCMSGetFromSender(data->self, from_addr, from_name, sender_addr,
                        sender_name);
 
   MimeCMSRequestAsyncSignatureVerification(
       data->content_info, from_addr.get(), from_name.get(), sender_addr.get(),
       sender_name.get(), data->smimeHeaderSink, aRelativeNestLevel,
-      data->item_data, data->item_len, data->hash_type);
+      data->url, data->item_data, data->item_len, data->hash_type);
 
   if (data->content_info) {
 #if 0  // XXX Fix this. What do we do here? //
     if (SEC_CMSContainsCertsOrCrls(data->content_info))
     {
       /* #### call libsec telling it to import the certs */
     }
 #endif