Implement basic PGP/Inline support for Encryption
authorAndre Heinecke <aheinecke@intevation.de>
Wed, 29 Nov 2017 12:15:37 +0000 (13:15 +0100)
committerAndre Heinecke <aheinecke@intevation.de>
Wed, 29 Nov 2017 12:15:37 +0000 (13:15 +0100)
* src/mail.cpp (Mail::encrypt_sign): Mark down if inline is
requested.
* src/mail.h (Mail::should_inline_crypt): New.
* src/mimedataprovider.cpp (MimeDataProvider::collect_input_lines):
Handle "MIME Inline" for our own sent messages.
* src/mimemaker.cpp (finalize_message): Handle is_inline.
(create_top_encryption_header): Handle is_inline to write
text/plain header.
(mime_encrypt): Support inline if no attachments exist.

--
This adds a first basic inline support. If the option
is set and a PGP Message without attachments is sent
the message will be sent as PGP Inline message.
Currently only supported for "Encrypt" not Encrypt / Sign.

GnuPG-Bug-Id: T3514

src/mail.cpp
src/mail.h
src/mimedataprovider.cpp
src/mimemaker.cpp

index 5728052..29caeca 100644 (file)
@@ -983,6 +983,8 @@ Mail::encrypt_sign ()
 
   const auto window = get_active_hwnd ();
 
+  m_do_inline = opt.inline_pgp;
+
   EnableWindow (window, FALSE);
   if (flags == 3)
     {
index 3885f34..2ea7834 100644 (file)
@@ -325,6 +325,9 @@ public:
   /** Check if all attachments are hidden and show a warning
     message appropiate to the crypto state if necessary. */
   int check_attachments () const;
+
+  /** Check if the mail should be encrypted "inline" */
+  bool should_inline_crypt () const {return m_do_inline;}
 private:
   void update_categories ();
   void update_body ();
@@ -355,5 +358,6 @@ private:
   GpgME::UserID m_uid;
   std::string m_uuid;
   std::string m_orig_body;
+  bool m_do_inline;
 };
 #endif // MAIL_H
index 4e825b8..a760486 100644 (file)
@@ -75,6 +75,7 @@ struct mime_context
   int collect_html_body;  /* True if we are collcting the html body */
   int collect_crypto_data; /* True if we are collecting the signed data. */
   int collect_signature;  /* True if we are collecting a signature.  */
+  int pgp_marker_checked; /* Checked if the first body line is pgp marker*/
   int is_encrypted;       /* True if we are working on an encrypted mail. */
   int start_hashing;      /* Flag used to start collecting signed data. */
   int hashing_level;      /* MIME level where we started hashing. */
@@ -611,6 +612,22 @@ MimeDataProvider::collect_input_lines(const char *input, size_t insize)
               return not_taken;
             }
 
+          /* Check if the first line of the body is actually
+             a PGP Inline message. If so treat it as crypto data. */
+          if (!m_mime_ctx->pgp_marker_checked && m_mime_ctx->collect_body == 2)
+            {
+              m_mime_ctx->pgp_marker_checked = true;
+              if (pos >= 27 && !strncmp ("-----BEGIN PGP MESSAGE-----", linebuf, 27))
+                {
+                  log_debug ("%s:%s: Found PGP Message in body.",
+                             SRCNAME, __func__);
+                  m_mime_ctx->collect_body = 0;
+                  m_mime_ctx->collect_crypto_data = 1;
+                  m_mime_ctx->start_hashing = 1;
+                  m_collect_everything = true;
+                }
+            }
+
           /* If we are currently in a collecting state actually
              collect that line */
           if (m_mime_ctx->collect_crypto_data && m_mime_ctx->start_hashing)
index 4bc6079..50d2485 100644 (file)
@@ -1072,7 +1072,6 @@ delete_all_attachments (LPMESSAGE message, mapi_attach_item_t *table)
 }
 
 
-
 /* Commit changes to the attachment ATTACH and release the object.
    SINK needs to be passed as well and will also be closed.  Note that
    the address of ATTACH is expected so that the fucntion can set it
@@ -1138,7 +1137,7 @@ cancel_mapi_attachment (LPATTACH *attach, sink_t sink)
 /* Do the final processing for a message. */
 static int
 finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table,
-                  protocol_t protocol, int encrypt)
+                  protocol_t protocol, int encrypt, bool is_inline = false)
 {
   HRESULT hr;
   SPropValue prop;
@@ -1176,7 +1175,18 @@ finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table,
   /* We also need to set the message class into our custom
      property. This override is at least required for encrypted
      messages.  */
-  if (mapi_set_gpgol_msg_class (message,
+  if (is_inline && mapi_set_gpgol_msg_class (message,
+                                          (encrypt?
+                                           (protocol == PROTOCOL_SMIME?
+                                            "IPM.Note.GpgOL.OpaqueEncrypted" :
+                                            "IPM.Note.GpgOL.PGPMessage") :
+                                            "IPM.Note.GpgOL.ClearSigned")))
+    {
+      log_error ("%s:%s: error setting gpgol msgclass",
+                 SRCNAME, __func__);
+      return -1;
+    }
+  if (!is_inline && mapi_set_gpgol_msg_class (message,
                                 (encrypt?
                                  (protocol == PROTOCOL_SMIME?
                                   "IPM.Note.GpgOL.OpaqueEncrypted" :
@@ -1188,15 +1198,6 @@ finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table,
       return -1;
     }
 
-  /* Now delete all parts of the MAPI message except for the one
-     attachment we just created.  */
-  if (delete_all_attachments (message, att_table))
-    {
-      log_error ("%s:%s: error deleting attachments",
-                 SRCNAME, __func__);
-      return -1;
-    }
-
   proparray.cValues = 1;
   proparray.aulPropTag[0] = PR_BODY;
   hr = message->DeleteProps (&proparray, NULL);
@@ -1215,6 +1216,15 @@ finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table,
                      SRCNAME, __func__);
     }
 
+  /* Now delete all parts of the MAPI message except for the one
+     attachment we just created.  */
+  if (delete_all_attachments (message, att_table))
+    {
+      log_error ("%s:%s: error deleting attachments",
+                 SRCNAME, __func__);
+      return -1;
+    }
+
   /* Remove the draft info so that we don't leak the information on
      whether the message has been signed etc.  */
   mapi_set_gpgol_draft_info (message, NULL);
@@ -1845,11 +1855,23 @@ sink_encryption_write_b64 (sink_t encsink, const void *data, size_t datalen)
    BOUNDARYSIZE+1 bytes which will be set on return from that
    function.  */
 static int
-create_top_encryption_header (sink_t sink, protocol_t protocol, char *boundary)
+create_top_encryption_header (sink_t sink, protocol_t protocol, char *boundary,
+                              bool is_inline = false)
 {
   int rc;
 
-  if (protocol == PROTOCOL_SMIME)
+  if (is_inline)
+    {
+      *boundary = 0;
+      rc = write_multistring (sink,
+                              "MIME-Version: 1.0\r\n"
+                              "Content-Type: text/plain;\r\n"
+                              "\tcharset=\"iso-8859-1\"\r\n"
+                              "Content-Transfer-Encoding: 7BIT\r\n"
+                              "\r\n",
+                              NULL);
+    }
+  else if (protocol == PROTOCOL_SMIME)
     {
       *boundary = 0;
       rc = write_multistring (sink,
@@ -1916,6 +1938,7 @@ mime_encrypt (LPMESSAGE message, HWND hwnd,
   int n_att_usable;
   engine_filter_t filter = NULL;
   char *my_sender = NULL;
+  bool is_inline = mail && mail->should_inline_crypt ();
 
   memset (sink, 0, sizeof *sink);
   memset (encsink, 0, sizeof *encsink);
@@ -1945,6 +1968,13 @@ mime_encrypt (LPMESSAGE message, HWND hwnd,
       goto failure;
     }
 
+  if (n_att_usable && is_inline)
+    {
+      log_debug ("%s:%s: PGP Inline not supported for attachments. Using PGP MIME",
+                 SRCNAME, __func__);
+      is_inline = false;
+    }
+
   /* Prepare the encryption.  We do this early as it is quite common
      that some recipient keys are not available and thus the
      encryption will fail early. */
@@ -1972,8 +2002,16 @@ mime_encrypt (LPMESSAGE message, HWND hwnd,
   if (protocol == PROTOCOL_UNKNOWN)
     goto failure;
 
+  if (protocol != PROTOCOL_OPENPGP)
+    {
+      log_debug ("%s:%s: Inline not supported for S/MIME. Using MIME",
+                 SRCNAME, __func__);
+      is_inline = false;
+    }
+
   /* Write the top header.  */
-  rc = create_top_encryption_header (sink, protocol, boundary);
+  rc = create_top_encryption_header (sink, protocol, boundary,
+                                     is_inline);
   if (rc)
     goto failure;
 
@@ -1982,9 +2020,20 @@ mime_encrypt (LPMESSAGE message, HWND hwnd,
   encsink->writefnc = sink_encryption_write;
 
   /* Add the plaintext */
-  if (add_body_and_attachments (encsink, message, att_table, mail,
-                                body, n_att_usable))
-    goto failure;
+  if (is_inline && body)
+    {
+      if ((rc = write_multistring (encsink, body, NULL)))
+        {
+          log_error ("%s:%s: Adding the body failed.",
+                     SRCNAME, __func__);
+          goto failure;
+        }
+    }
+  else if (add_body_and_attachments (encsink, message, att_table, mail,
+                                     body, n_att_usable))
+    {
+      goto failure;
+    }
 
   xfree (body);
   body = NULL;
@@ -2011,7 +2060,7 @@ mime_encrypt (LPMESSAGE message, HWND hwnd,
   if (close_mapi_attachment (&attach, sink))
     goto failure;
 
-  if (finalize_message (message, att_table, protocol, 1))
+  if (finalize_message (message, att_table, protocol, 1, is_inline))
     goto failure;
 
   result = 0;  /* Everything is fine, fall through the cleanup now.  */