[git] GnuPG - branch, master, updated. gnupg-2.1.15-181-g3380028

by Werner Koch cvs at cvs.gnupg.org
Thu Sep 29 18:03:06 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  33800280da55a859e08dfa57f29144c89dd1bead (commit)
       via  c738f92c195d91662ddc7848cc3c92c7f091f1f8 (commit)
       via  f776757ea94542e2f425840dddaf3e65b0ff7757 (commit)
       via  29db3be6e8dbc9b4dd52cd1781106fa9fa3954a5 (commit)
       via  95d60c6ce9e8a7a7741553af957978c1f91547c5 (commit)
       via  4ac138c84d0f344ca9442f90c96f0e1f76062a4a (commit)
      from  9e6f8a55ed04f876635792125858ee76a948802a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 33800280da55a859e08dfa57f29144c89dd1bead
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 29 17:55:32 2016 +0200

    wks: Partly implement draft-koch-openpgp-webkey-service-02.
    
    * tools/gpg-wks.h (WKS_RECEIVE_DRAFT2): New.
    * tools/wks-receive.c: Include rfc822parse.h.
    (struct receive_ctx_s): Add fields PARSER, DRAFT_VERSION_2, and
    MULTIPART_MIXED_SEEN.
    (decrypt_data): Add --no-options.
    (verify_signature): Ditto.
    (new_part): Check for Wks-Draft-Version header.  Take care of text
    parts.
    (wks_receive): Set Parser and pass a flag value to RESULT_CB.
    * tools/gpg-wks-client.c (read_confirmation_request): New.
    (main) <aRead>: Call read_confirmation_request instead of
    process_confirmation_request.
    (command_receive_cb): Ditto.  Add arg FLAGS..
    (decrypt_stream_status_cb, decrypt_stream): New.
    (command_send): Set header Wks-Draft-Version.
    * tools/gpg-wks-server.c (struct server_ctx_s): Add field
    DRAFT_VERSION_2.
    (sign_stream_status_cb, sign_stream): New.
    (command_receive_cb): Set draft flag.
    (send_confirmation_request): Rework to implement protocol draft
    version 2.
    
    * tools/gpg-wks.h (DBG_MIME_VALUE, DBG_PARSER_VALUE): New.
    (DBG_MIME, DBG_PARSER, DBG_CRYPTO): New.  Use instead of a plain
    opt.debug where useful.
    * tools/gpg-wks-client.c (debug_flags): Add "mime" and "parser".
    * tools/gpg-wks-server.c (debug_flags): Ditto.
    --
    
    If a client supporting the version 2 of the protocol is used, it will
    tell this the server using a mail header.  An old server will ignore
    that but a recent server will use the new protocol.  Next task is to
    actually write draft-02.
    
    There are still a lot of FIXMEs - take care.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c
index 143dbc8..f4257ec 100644
--- a/tools/gpg-wks-client.c
+++ b/tools/gpg-wks-client.c
@@ -91,6 +91,8 @@ static ARGPARSE_OPTS opts[] = {
 /* The list of supported debug flags.  */
 static struct debug_flags_s debug_flags [] =
   {
+    { DBG_MIME_VALUE   , "mime"    },
+    { DBG_PARSER_VALUE , "parser"  },
     { DBG_CRYPTO_VALUE , "crypto"  },
     { DBG_MEMORY_VALUE , "memory"  },
     { DBG_MEMSTAT_VALUE, "memstat" },
@@ -103,9 +105,10 @@ static struct debug_flags_s debug_flags [] =
 static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
 static gpg_error_t command_supported (char *userid);
 static gpg_error_t command_send (const char *fingerprint, char *userid);
-static gpg_error_t process_confirmation_request (estream_t msg);
+static gpg_error_t read_confirmation_request (estream_t msg);
 static gpg_error_t command_receive_cb (void *opaque,
-                                       const char *mediatype, estream_t fp);
+                                       const char *mediatype, estream_t fp,
+                                       unsigned int flags);
 
 
 

@@ -269,7 +272,7 @@ main (int argc, char **argv)
     case aRead:
       if (argc)
         wrong_args ("--read < WKS-DATA");
-      err = process_confirmation_request (es_stdin);
+      err = read_confirmation_request (es_stdin);
       if (err)
         log_error ("processing mail failed: %s\n", gpg_strerror (err));
       break;
@@ -394,6 +397,83 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
 
 
 

+static void
+decrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
+{
+  (void)opaque;
+
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
+}
+
+
+/* Decrypt the INPUT stream to a new stream which is stored at success
+ * at R_OUTPUT.  */
+static gpg_error_t
+decrypt_stream (estream_t *r_output, estream_t input)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  estream_t output;
+
+  *r_output = NULL;
+
+  output = es_fopenmem (0, "w+b");
+  if (!output)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  /* We limit the output to 64 KiB to avoid DoS using compression
+   * tricks.  A regular client will anyway only send a minimal key;
+   * that is one w/o key signatures and attribute packets.  */
+  ccparray_put (&ccp, "--max-output=0x10000");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--decrypt");
+  ccparray_put (&ccp, "--");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
+                                NULL, output,
+                                decrypt_stream_status_cb, NULL);
+  if (err)
+    {
+      log_error ("decryption failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+  else if (opt.verbose)
+    log_info ("decryption succeeded\n");
+
+  es_rewind (output);
+  *r_output = output;
+  output = NULL;
+
+ leave:
+  es_fclose (output);
+  xfree (argv);
+  return err;
+}
+
+
+
+

 /* Check whether the  provider supports the WKS protocol.  */
 static gpg_error_t
 command_supported (char *userid)
@@ -517,6 +597,11 @@ command_send (const char *fingerprint, char *userid)
   if (err)
     goto leave;
 
+  /* Tell server that we support draft version 3.  */
+  err = mime_maker_add_header (mime, "Wks-Draft-Version", "3");
+  if (err)
+    goto leave;
+
   err = mime_maker_add_stream (mime, &key);
   if (err)
     goto leave;
@@ -539,8 +624,8 @@ encrypt_response_status_cb (void *opaque, const char *keyword, char *args)
   gpg_error_t *failure = opaque;
   char *fields[2];
 
-  if (opt.debug)
-    log_debug ("%s: %s\n", keyword, args);
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
 
   if (!strcmp (keyword, "FAILURE"))
     {
@@ -747,7 +832,7 @@ process_confirmation_request (estream_t msg)
       goto leave;
     }
 
-  if (opt.debug)
+  if (DBG_MIME)
     {
       log_debug ("request follows:\n");
       nvc_write (nvc, log_get_stream ());
@@ -822,16 +907,62 @@ process_confirmation_request (estream_t msg)
 }
 
 
+/* Read a confirmation request and decrypt it if needed.  This
+ * function may not be used with a mail or MIME message but only with
+ * the actual encrypted or plaintext WKS data.  */
+static gpg_error_t
+read_confirmation_request (estream_t msg)
+{
+  gpg_error_t err;
+  int c;
+  estream_t plaintext = NULL;
+
+  /* We take a really simple approach to check whether MSG is
+   * encrypted: We know that an encrypted message is always armored
+   * and thus starts with a few dashes.  It is even sufficient to
+   * check for a single dash, because that can never be a proper first
+   * WKS data octet.  We need to skip leading spaces, though. */
+  while ((c = es_fgetc (msg)) == ' ' || c == '\t' || c == '\r' || c == '\n')
+    ;
+  if (c == EOF)
+    {
+      log_error ("can't process an empty message\n");
+      return gpg_error (GPG_ERR_INV_DATA);
+    }
+  if (es_ungetc (c, msg) != c)
+    {
+      log_error ("error ungetting octet from message\n");
+      return gpg_error (GPG_ERR_INTERNAL);
+    }
+
+  if (c != '-')
+    err = process_confirmation_request (msg);
+  else
+    {
+      err = decrypt_stream (&plaintext, msg);
+      if (err)
+        log_error ("decryption failed: %s\n", gpg_strerror (err));
+      else
+        err = process_confirmation_request (plaintext);
+    }
+
+  es_fclose (plaintext);
+  return err;
+}
+
+
 /* Called from the MIME receiver to process the plain text data in MSG.  */
 static gpg_error_t
-command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
+command_receive_cb (void *opaque, const char *mediatype,
+                    estream_t msg, unsigned int flags)
 {
   gpg_error_t err;
 
   (void)opaque;
+  (void)flags;
 
   if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
-    err = process_confirmation_request (msg);
+    err = read_confirmation_request (msg);
   else
     {
       log_info ("ignoring unexpected message of type '%s'\n", mediatype);
diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c
index 96e5e05..408e3f5 100644
--- a/tools/gpg-wks-server.c
+++ b/tools/gpg-wks-server.c
@@ -102,6 +102,8 @@ static ARGPARSE_OPTS opts[] = {
 /* The list of supported debug flags.  */
 static struct debug_flags_s debug_flags [] =
   {
+    { DBG_MIME_VALUE   , "mime"    },
+    { DBG_PARSER_VALUE , "parser"  },
     { DBG_CRYPTO_VALUE , "crypto"  },
     { DBG_MEMORY_VALUE , "memory"  },
     { DBG_MEMSTAT_VALUE, "memstat" },
@@ -116,6 +118,7 @@ struct server_ctx_s
 {
   char *fpr;
   strlist_t mboxes;  /* List of addr-specs taken from the UIDs.  */
+  unsigned int draft_version_2:1; /* Client supports the draft 2.  */
 };
 typedef struct server_ctx_s *server_ctx_t;
 
@@ -123,7 +126,8 @@ typedef struct server_ctx_s *server_ctx_t;
 static gpg_error_t get_domain_list (strlist_t *r_list);
 
 static gpg_error_t command_receive_cb (void *opaque,
-                                       const char *mediatype, estream_t fp);
+                                       const char *mediatype, estream_t fp,
+                                       unsigned int flags);
 static gpg_error_t command_list_domains (void);
 static gpg_error_t command_cron (void);
 
@@ -350,8 +354,8 @@ list_key_status_cb (void *opaque, const char *keyword, char *args)
 {
   server_ctx_t ctx = opaque;
   (void)ctx;
-  if (opt.debug)
-    log_debug ("%s: %s\n", keyword, args);
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
 }
 
 
@@ -629,8 +633,8 @@ encrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
 {
   (void)opaque;
 
-  if (opt.debug)
-    log_debug ("%s: %s\n", keyword, args);
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
 }
 
 
@@ -698,6 +702,78 @@ encrypt_stream (estream_t *r_output, estream_t input, const char *keyfile)
 }
 
 
+static void
+sign_stream_status_cb (void *opaque, const char *keyword, char *args)
+{
+  (void)opaque;
+
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
+}
+
+/* Sign the INPUT stream to a new stream which is stored at success at
+ * R_OUTPUT.  A detached signature is created using the key specified
+ * by USERID.  */
+static gpg_error_t
+sign_stream (estream_t *r_output, estream_t input, const char *userid)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  estream_t output;
+
+  *r_output = NULL;
+
+  output = es_fopenmem (0, "w+b");
+  if (!output)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--armor");
+  ccparray_put (&ccp, "--local-user");
+  ccparray_put (&ccp, userid);
+  ccparray_put (&ccp, "--detach-sign");
+  ccparray_put (&ccp, "--");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
+                                NULL, output,
+                                sign_stream_status_cb, NULL);
+  if (err)
+    {
+      log_error ("signing failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  es_rewind (output);
+  *r_output = output;
+  output = NULL;
+
+ leave:
+  es_fclose (output);
+  xfree (argv);
+  return err;
+}
+
+
 /* Get the submission address for address MBOX.  Caller must free the
  * value.  If no address can be found NULL is returned.  */
 static char *
@@ -933,6 +1009,8 @@ send_confirmation_request (server_ctx_t ctx,
   gpg_error_t err;
   estream_t body = NULL;
   estream_t bodyenc = NULL;
+  estream_t signeddata = NULL;
+  estream_t signature = NULL;
   mime_maker_t mime = NULL;
   char *from_buffer = NULL;
   const char *from;
@@ -958,12 +1036,16 @@ send_confirmation_request (server_ctx_t ctx,
       log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
       goto leave;
     }
-  /* It is fine to use 8 bit encoding because that is encrypted and
-   * only our client will see it.  */
-  es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
-            "Content-Transfer-Encoding: 8bit\n"
-            "\n",
-            body);
+
+  if (!ctx->draft_version_2)
+    {
+      /* It is fine to use 8 bit encoding because that is encrypted and
+       * only our client will see it.  */
+      es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
+                "Content-Transfer-Encoding: 8bit\n"
+                "\n",
+                body);
+    }
 
   es_fprintf (body, ("type: confirmation-request\n"
                      "sender: %s\n"
@@ -1002,35 +1084,117 @@ send_confirmation_request (server_ctx_t ctx,
         goto leave;
     }
 
-  err = mime_maker_add_header (mime, "Content-Type",
-                               "multipart/encrypted; "
-                               "protocol=\"application/pgp-encrypted\"");
-  if (err)
-    goto leave;
-  err = mime_maker_add_container (mime);
-  if (err)
-    goto leave;
+  if (!ctx->draft_version_2)
+    {
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "multipart/encrypted; "
+                                   "protocol=\"application/pgp-encrypted\"");
+      if (err)
+        goto leave;
+      err = mime_maker_add_container (mime);
+      if (err)
+        goto leave;
 
-  err = mime_maker_add_header (mime, "Content-Type",
-                               "application/pgp-encrypted");
-  if (err)
-    goto leave;
-  err = mime_maker_add_body (mime, "Version: 1\n");
-  if (err)
-    goto leave;
-  err = mime_maker_add_header (mime, "Content-Type",
-                               "application/octet-stream");
-  if (err)
-    goto leave;
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/pgp-encrypted");
+      if (err)
+        goto leave;
+      err = mime_maker_add_body (mime, "Version: 1\n");
+      if (err)
+        goto leave;
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/octet-stream");
+      if (err)
+        goto leave;
 
-  err = mime_maker_add_stream (mime, &bodyenc);
-  if (err)
-    goto leave;
+      err = mime_maker_add_stream (mime, &bodyenc);
+      if (err)
+        goto leave;
+
+    }
+  else
+    {
+      unsigned int partid;
+
+      /* FIXME: Add micalg.  */
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "multipart/signed; "
+                                   "protocol=\"application/pgp-signature\"");
+      if (err)
+        goto leave;
+      err = mime_maker_add_container (mime);
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_container (mime);
+      if (err)
+        goto leave;
+      partid = mime_maker_get_partid (mime);
+
+      err = mime_maker_add_header (mime, "Content-Type", "text/plain");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_body
+        (mime,
+         "This message has been send to confirm your request\n"
+         "to publish your key.  If you did not request a key\n"
+         "publication, simply ignore this message.\n"
+         "\n"
+         "Most mail software can handle this kind of message\n"
+         "automatically and thus you would not have seen this\n"
+         "message.  It seems that your client does not fully\n"
+         "support this service.  The web page\n"
+         "\n"
+         "       https://gnupg.org/faq/wkd.html\n"
+         "\n"
+         "explains how you can process this message anyway in\n"
+         "a few manual steps.\n");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/vnd.gnupg.wks");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_stream (mime, &bodyenc);
+      if (err)
+        goto leave;
+
+      err = mime_maker_end_container (mime);
+      if (err)
+        goto leave;
+
+      mime_maker_dump_tree (mime);
+      err = mime_maker_get_part (mime, partid, &signeddata);
+      if (err)
+        goto leave;
+
+      err = sign_stream (&signature, signeddata, from);
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/pgp-signature");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_stream (mime, &signature);
+      if (err)
+        goto leave;
+    }
 
   err = wks_send_mime (mime);
 
  leave:
   mime_maker_release (mime);
+  es_fclose (signature);
+  es_fclose (signeddata);
   es_fclose (bodyenc);
   es_fclose (body);
   xfree (from_buffer);
@@ -1478,15 +1642,18 @@ process_confirmation_response (server_ctx_t ctx, estream_t msg)
 

 /* Called from the MIME receiver to process the plain text data in MSG .  */
 static gpg_error_t
-command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
+command_receive_cb (void *opaque, const char *mediatype,
+                    estream_t msg, unsigned int flags)
 {
   gpg_error_t err;
   struct server_ctx_s ctx;
 
-  memset (&ctx, 0, sizeof ctx);
-
   (void)opaque;
 
+  memset (&ctx, 0, sizeof ctx);
+  if ((flags & WKS_RECEIVE_DRAFT2))
+    ctx.draft_version_2 = 1;
+
   if (!strcmp (mediatype, "application/pgp-keys"))
     err = process_new_key (&ctx, msg);
   else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h
index 85000cc..f8b6cfd 100644
--- a/tools/gpg-wks.h
+++ b/tools/gpg-wks.h
@@ -39,12 +39,18 @@ struct
 } opt;
 
 /* Debug values and macros.  */
+#define DBG_MIME_VALUE        1 /* Debug the MIME structure.  */
+#define DBG_PARSER_VALUE      2 /* Debug the Mail parser.  */
 #define DBG_CRYPTO_VALUE      4	/* Debug low level crypto.  */
 #define DBG_MEMORY_VALUE     32	/* Debug memory allocation stuff.  */
 #define DBG_MEMSTAT_VALUE   128	/* Show memory statistics.  */
 #define DBG_IPC_VALUE      1024 /* Debug assuan communication.  */
 #define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
 
+#define DBG_MIME     (opt.debug & DBG_MIME_VALUE)
+#define DBG_PARSER   (opt.debug & DBG_PARSER_VALUE)
+#define DBG_CRYPTO   (opt.debug & DBG_CRYPTO_VALUE)
+
 
 /* The parsed policy flags. */
 struct policy_flags_s
@@ -64,10 +70,15 @@ gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
                               int ignore_unknown);
 
 /*-- wks-receive.c --*/
+
+/* Flag values for the receive callback.  */
+#define WKS_RECEIVE_DRAFT2 1
+
 gpg_error_t wks_receive (estream_t fp,
                          gpg_error_t (*result_cb)(void *opaque,
                                                   const char *mediatype,
-                                                  estream_t data),
+                                                  estream_t data,
+                                                  unsigned int flags),
                          void *cb_data);
 
 
diff --git a/tools/wks-receive.c b/tools/wks-receive.c
index 59141fc..0deca9b 100644
--- a/tools/wks-receive.c
+++ b/tools/wks-receive.c
@@ -26,6 +26,7 @@
 #include "ccparray.h"
 #include "exectool.h"
 #include "gpg-wks.h"
+#include "rfc822parse.h"
 #include "mime-parser.h"
 
 
@@ -41,6 +42,7 @@
 /* Data for a received object.  */
 struct receive_ctx_s
 {
+  mime_parser_t parser;
   estream_t encrypted;
   estream_t plaintext;
   estream_t signeddata;
@@ -49,6 +51,8 @@ struct receive_ctx_s
   estream_t wkd_data;
   unsigned int collect_key_data:1;
   unsigned int collect_wkd_data:1;
+  unsigned int draft_version_2:1;  /* This is a draft version 2 request.  */
+  unsigned int multipart_mixed_seen:1;
 };
 typedef struct receive_ctx_s *receive_ctx_t;
 
@@ -59,7 +63,8 @@ decrypt_data_status_cb (void *opaque, const char *keyword, char *args)
 {
   receive_ctx_t ctx = opaque;
   (void)ctx;
-  log_debug ("%s: %s\n", keyword, args);
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
 }
 
 
@@ -86,6 +91,7 @@ decrypt_data (receive_ctx_t ctx)
 
   ccparray_init (&ccp, 0);
 
+  ccparray_put (&ccp, "--no-options");
   /* We limit the output to 64 KiB to avoid DoS using compression
    * tricks.  A regular client will anyway only send a minimal key;
    * that is one w/o key signatures and attribute packets.  */
@@ -113,7 +119,7 @@ decrypt_data (receive_ctx_t ctx)
       goto leave;
     }
 
-  if (opt.debug)
+  if (DBG_CRYPTO)
     {
       es_rewind (ctx->plaintext);
       log_debug ("plaintext: '");
@@ -133,7 +139,8 @@ verify_signature_status_cb (void *opaque, const char *keyword, char *args)
 {
   receive_ctx_t ctx = opaque;
   (void)ctx;
-  log_debug ("%s: %s\n", keyword, args);
+  if (DBG_CRYPTO)
+    log_debug ("gpg status: %s %s\n", keyword, args);
 }
 
 /* Verify the signed data.  */
@@ -151,6 +158,7 @@ verify_signature (receive_ctx_t ctx)
 
   ccparray_init (&ccp, 0);
 
+  ccparray_put (&ccp, "--no-options");
   ccparray_put (&ccp, "--batch");
   if (opt.verbose)
     ccparray_put (&ccp, "--verbose");
@@ -177,6 +185,8 @@ verify_signature (receive_ctx_t ctx)
       goto leave;
     }
 
+  log_debug ("Fixme: Verification result is not used\n");
+
  leave:
   xfree (argv);
 }
@@ -264,6 +274,22 @@ new_part (void *cookie, const char *mediatype, const char *mediasubtype)
         }
       else
         {
+          rfc822parse_t msg = mime_parser_rfc822parser (ctx->parser);
+          if (msg)
+            {
+              char *value;
+              size_t valueoff;
+
+              value = rfc822parse_get_field (msg, "Wks-Draft-Version",
+                                             -1, &valueoff);
+              if (value)
+                {
+                  if (atoi(value+valueoff) >= 2 )
+                    ctx->draft_version_2 = 1;
+                  free (value);
+                }
+            }
+
           ctx->key_data = es_fopenmem (0, "w+b");
           if (!ctx->key_data)
             {
@@ -303,6 +329,19 @@ new_part (void *cookie, const char *mediatype, const char *mediasubtype)
             }
         }
     }
+  else if (!strcmp (mediatype, "multipart")
+           && !strcmp (mediasubtype, "mixed"))
+    {
+      ctx->multipart_mixed_seen = 1;
+    }
+  else if (!strcmp (mediatype, "text"))
+    {
+      /* Check that we receive a text part only after a
+       * application/mixed.  This is actually a too simple test and we
+       * should eventually employ a strict MIME structure check.  */
+      if (!ctx->multipart_mixed_seen)
+        err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
+    }
   else
     {
       log_error ("unexpected '%s/%s' message part\n", mediatype, mediasubtype);
@@ -320,7 +359,7 @@ part_data (void *cookie, const void *data, size_t datalen)
 
   if (data)
     {
-      if (opt.debug)
+      if (DBG_MIME)
         log_debug ("part_data: '%.*s'\n", (int)datalen, (const char*)data);
       if (ctx->collect_key_data)
         {
@@ -337,7 +376,7 @@ part_data (void *cookie, const void *data, size_t datalen)
     }
   else
     {
-      if (opt.debug)
+      if (DBG_MIME)
         log_debug ("part_data: finished\n");
       ctx->collect_key_data = 0;
       ctx->collect_wkd_data = 0;
@@ -353,7 +392,8 @@ gpg_error_t
 wks_receive (estream_t fp,
              gpg_error_t (*result_cb)(void *opaque,
                                       const char *mediatype,
-                                      estream_t data),
+                                      estream_t data,
+                                      unsigned int flags),
              void *cb_data)
 {
   gpg_error_t err;
@@ -361,6 +401,7 @@ wks_receive (estream_t fp,
   mime_parser_t parser;
   estream_t plaintext = NULL;
   int c;
+  unsigned int flags = 0;
 
   ctx = xtrycalloc (1, sizeof *ctx);
   if (!ctx)
@@ -369,14 +410,16 @@ wks_receive (estream_t fp,
   err = mime_parser_new (&parser, ctx);
   if (err)
     goto leave;
-  if (opt.verbose > 1 || opt.debug)
-    mime_parser_set_verbose (parser, opt.debug? 10: 1);
+  if (DBG_PARSER)
+    mime_parser_set_verbose (parser, 1);
   mime_parser_set_new_part (parser, new_part);
   mime_parser_set_part_data (parser, part_data);
   mime_parser_set_collect_encrypted (parser, collect_encrypted);
   mime_parser_set_collect_signeddata (parser, collect_signeddata);
   mime_parser_set_collect_signature (parser, collect_signature);
 
+  ctx->parser = parser;
+
   err = mime_parser_parse (parser, fp);
   if (err)
     goto leave;
@@ -385,6 +428,11 @@ wks_receive (estream_t fp,
     log_info ("key data found\n");
   if (ctx->wkd_data)
     log_info ("wkd data found\n");
+  if (ctx->draft_version_2)
+    {
+      log_info ("draft version 2 requested\n");
+      flags |= WKS_RECEIVE_DRAFT2;
+    }
 
   if (ctx->plaintext)
     {
@@ -412,7 +460,7 @@ wks_receive (estream_t fp,
 
   if (ctx->key_data)
     {
-      if (opt.debug)
+      if (DBG_MIME)
         {
           es_rewind (ctx->key_data);
           log_debug ("Key: '");
@@ -424,14 +472,15 @@ wks_receive (estream_t fp,
       if (result_cb)
         {
           es_rewind (ctx->key_data);
-          err = result_cb (cb_data, "application/pgp-keys", ctx->key_data);
+          err = result_cb (cb_data, "application/pgp-keys",
+                           ctx->key_data, flags);
           if (err)
             goto leave;
         }
     }
   if (ctx->wkd_data)
     {
-      if (opt.debug)
+      if (DBG_MIME)
         {
           es_rewind (ctx->wkd_data);
           log_debug ("WKD: '");
@@ -443,7 +492,8 @@ wks_receive (estream_t fp,
       if (result_cb)
         {
           es_rewind (ctx->wkd_data);
-          err = result_cb (cb_data, "application/vnd.gnupg.wks", ctx->wkd_data);
+          err = result_cb (cb_data, "application/vnd.gnupg.wks",
+                           ctx->wkd_data, flags);
           if (err)
             goto leave;
         }
@@ -453,6 +503,7 @@ wks_receive (estream_t fp,
  leave:
   es_fclose (plaintext);
   mime_parser_release (parser);
+  ctx->parser = NULL;
   es_fclose (ctx->encrypted);
   es_fclose (ctx->plaintext);
   es_fclose (ctx->signeddata);

commit c738f92c195d91662ddc7848cc3c92c7f091f1f8
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 29 17:59:09 2016 +0200

    tools: Convey signeddata also to the part_data callback in mime-parser.
    
    * tools/mime-parser.c (mime_parser_parse): Factor some code out to ...
    (process_part_data): new.
    ((mime_parser_parse): Also call process_part_data for signed data.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/mime-parser.c b/tools/mime-parser.c
index 0ca5452..9017810 100644
--- a/tools/mime-parser.c
+++ b/tools/mime-parser.c
@@ -616,6 +616,35 @@ mime_parser_rfc822parser (mime_parser_t ctx)
 }
 
 
+/* Helper for mime_parser_parse.  */
+static gpg_error_t
+process_part_data (mime_parser_t ctx, char *line, size_t *length)
+{
+  gpg_error_t err;
+  size_t nbytes;
+
+  if (!ctx->want_part)
+    return 0;
+  if (!ctx->part_data)
+    return 0;
+
+  if (ctx->decode_part == 1)
+    {
+      *length = qp_decode (line, *length, NULL);
+    }
+  else if (ctx->decode_part == 2)
+    {
+      log_assert (ctx->b64state);
+      err = b64dec_proc (ctx->b64state, line, *length, &nbytes);
+      if (err)
+        return err;
+      *length = nbytes;
+    }
+
+  return ctx->part_data (ctx->cookie, line, *length);
+}
+
+
 /* Read and parse a message from FP and call the appropriate
  * callbacks.  */
 gpg_error_t
@@ -624,7 +653,7 @@ mime_parser_parse (mime_parser_t ctx, estream_t fp)
   gpg_error_t err;
   rfc822parse_t msg = NULL;
   unsigned int lineno = 0;
-  size_t length, nbytes;
+  size_t length;
   char *line;
 
   line = ctx->line;
@@ -741,6 +770,10 @@ mime_parser_parse (mime_parser_t ctx, estream_t fp)
               ctx->collect_signeddata (ctx->cookie, line);
             }
           ctx->delay_hashing = 1;
+
+          err = process_part_data (ctx, line, &length);
+          if (err)
+            goto leave;
         }
       else if (ctx->pgpmime == PGPMIME_IN_SIGNATURE)
         {
@@ -756,26 +789,11 @@ mime_parser_parse (mime_parser_t ctx, estream_t fp)
           if (ctx->collect_signeddata)
             ctx->collect_signature (ctx->cookie, NULL);
         }
-      else if (ctx->want_part)
+      else
         {
-          if (ctx->part_data)
-            {
-              if (ctx->decode_part == 1)
-                {
-                  length = qp_decode (line, length, NULL);
-                }
-              else if (ctx->decode_part == 2)
-                {
-                  log_assert (ctx->b64state);
-                  err = b64dec_proc (ctx->b64state, line, length, &nbytes);
-                  if (err)
-                    goto leave;
-                  length = nbytes;
-                }
-              err = ctx->part_data (ctx->cookie, line, length);
-              if (err)
-                goto leave;
-            }
+          err = process_part_data (ctx, line, &length);
+          if (err)
+            goto leave;
         }
     }
 

commit f776757ea94542e2f425840dddaf3e65b0ff7757
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 29 17:38:06 2016 +0200

    tools: Allow retrieval of signed data from mime-maker.
    
    * tools/mime-maker.c (find_part): New.
    (mime_maker_get_part): New.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/mime-maker.c b/tools/mime-maker.c
index 99185cf..a81bd69 100644
--- a/tools/mime-maker.c
+++ b/tools/mime-maker.c
@@ -202,6 +202,22 @@ find_parent (part_t root, part_t needle)
   return NULL;
 }
 
+/* Find the part node from the PARTID.  */
+static part_t
+find_part (part_t root, unsigned int partid)
+{
+  part_t node, n;
+
+  for (node = root->child; node; node = node->next)
+    {
+      if (node->partid == partid)
+        return root;
+      if ((n = find_part (node, partid)))
+        return n;
+    }
+  return NULL;
+}
+
 
 /* Create a boundary string.  Outr codes is aware of the general
  * structure of that string (gebins with "=-=") so that
@@ -730,3 +746,54 @@ mime_maker_make (mime_maker_t ctx, estream_t fp)
   ctx->outfp = NULL;
   return err;
 }
+
+
+/* Create a stream object from the MIME part identified by PARTID and
+ * store it at R_STREAM.  If PARTID identifies a container the entire
+ * tree is returned. Using that function may read stream objects
+ * which have been added as MIME bodies.  The caller must close the
+ * stream object. */
+gpg_error_t
+mime_maker_get_part (mime_maker_t ctx, unsigned int partid, estream_t *r_stream)
+{
+  gpg_error_t err;
+  part_t part;
+  estream_t fp;
+
+  *r_stream = NULL;
+
+  /* When the entire tree is requested, we make sure that all missing
+   * headers are applied.  We don't do that if only a part is
+   * requested because the additional headers (like Date:) will only
+   * be added to part 0 headers anyway. */
+  if (!partid)
+    {
+       err = add_missing_headers (ctx);
+       if (err)
+         return err;
+       part = ctx->mail;
+    }
+  else
+    part = find_part (ctx->mail, partid);
+
+  /* For now we use a memory stream object; however it would also be
+   * possible to create an object created on the fly while the caller
+   * is reading the returned stream.  */
+  fp = es_fopenmem (0, "w+b");
+  if (!fp)
+    return gpg_error_from_syserror ();
+
+  ctx->outfp = fp;
+  err = write_tree (ctx, NULL, part);
+  ctx->outfp = NULL;
+
+  if (!err)
+    {
+      es_rewind (fp);
+      *r_stream = fp;
+    }
+  else
+    es_fclose (fp);
+
+  return err;
+}
diff --git a/tools/mime-maker.h b/tools/mime-maker.h
index 2fac9c3..23047c3 100644
--- a/tools/mime-maker.h
+++ b/tools/mime-maker.h
@@ -39,6 +39,8 @@ gpg_error_t mime_maker_end_container (mime_maker_t ctx);
 unsigned int mime_maker_get_partid (mime_maker_t ctx);
 
 gpg_error_t mime_maker_make (mime_maker_t ctx, estream_t fp);
+gpg_error_t mime_maker_get_part (mime_maker_t ctx, unsigned int partid,
+                                 estream_t *r_stream);
 
 
 

commit 29db3be6e8dbc9b4dd52cd1781106fa9fa3954a5
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 29 12:29:27 2016 +0200

    tools: Change mime-maker to write out CR,LF.
    
    * tools/mime-maker.c (struct part_s): Add field PARTID.
    (struct mime_maker_context_s): Add field PARTID_COUNTER.
    (dump_parts): Print part ids.
    (mime_maker_add_header): Assign PARTID.
    (mime_maker_add_container): Ditto.
    (mime_maker_get_partid): New.
    (write_ct_with_boundary): Remove.
    (add_header): Strip trailing white spaces.
    (write_header): Remove trailing spaces trimming.  Add arg BOUNDARY.
    Handle emdedded LFs.
    (write_gap, write_boundary, write_body): New.
    (write_tree): Use new functions.
    --
    
    These changes prepare for forthcoming enhancements.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/mime-maker.c b/tools/mime-maker.c
index 07783d9..99185cf 100644
--- a/tools/mime-maker.c
+++ b/tools/mime-maker.c
@@ -54,6 +54,7 @@ struct part_s
   size_t bodylen;       /* Length of BODY.   */
   char *body;           /* Malloced buffer with the body.  This is the
                          * non-encoded value.  */
+  unsigned int partid;   /* The part ID.  */
 };
 typedef struct part_s *part_t;
 
@@ -70,6 +71,8 @@ struct mime_maker_context_s
   part_t mail;                 /* The MIME tree.  */
   part_t current_part;
 
+  unsigned int partid_counter; /* Counter assign part ids.  */
+
   int boundary_counter;  /* Used to create easy to read boundaries.  */
   char *boundary_suffix; /* Random string used in the boundaries.  */
 
@@ -159,7 +162,7 @@ dump_parts (part_t part, int level)
 
   for (; part; part = part->next)
     {
-      log_debug ("%*s[part]\n", level*2, "");
+      log_debug ("%*s[part %u]\n", level*2, "", part->partid);
       for (hdr = part->headers; hdr; hdr = hdr->next)
         {
           log_debug ("%*s%s: %s\n", level*2, "", hdr->name, hdr->value);
@@ -300,6 +303,7 @@ add_header (part_t part, const char *name, const char *value)
   header_t hdr;
   size_t namelen;
   const char *s;
+  char *p;
 
   if (!value)
     {
@@ -338,6 +342,18 @@ add_header (part_t part, const char *name, const char *value)
       return err;
     }
 
+  for (p = hdr->value + strlen (hdr->value) - 1;
+       (p >= hdr->value
+        && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'));
+       p--)
+    *p = 0;
+  if (!(p >= hdr->value))
+    {
+      xfree (hdr->value);
+      xfree (hdr);
+      return gpg_error (GPG_ERR_INV_VALUE);  /* Only spaces.  */
+    }
+
   if (part)
     {
       *part->headers_tail = hdr;
@@ -390,6 +406,7 @@ mime_maker_add_header (mime_maker_t ctx, const char *name, const char *value)
       part = xtrycalloc (1, sizeof *part);
       if (!part)
         return gpg_error_from_syserror ();
+      part->partid = ++ctx->partid_counter;
       part->headers_tail = &part->headers;
       log_assert (!ctx->current_part->next);
       ctx->current_part->next = part;
@@ -507,6 +524,7 @@ mime_maker_add_container (mime_maker_t ctx)
     }
 
   part = part->child;
+  part->partid = ++ctx->partid_counter;
   ctx->current_part = part;
 
   return 0;
@@ -532,31 +550,79 @@ mime_maker_end_container (mime_maker_t ctx)
 }
 
 
-/* Write the Content-Type header with the boundary value.  */
+/* Return the part-ID of the current part. */
+unsigned int
+mime_maker_get_partid (mime_maker_t ctx)
+{
+  if (ensure_part (ctx, NULL))
+    return 0; /* Ooops.  */
+  return ctx->current_part->partid;
+}
+
+
+/* Write a header and handle emdedded LFs.  If BOUNDARY is not NULL it
+ * is appended to the value.  */
+/* Fixme: Add automatic line wrapping.  */
 static gpg_error_t
-write_ct_with_boundary (mime_maker_t ctx,
-                        const char *value, const char *boundary)
+write_header (mime_maker_t ctx, const char *name, const char *value,
+              const char *boundary)
 {
   const char *s;
 
-  if (!*value)
-    return gpg_error (GPG_ERR_INV_VALUE);  /* Empty string.  */
-
-  for (s=value + strlen (value) - 1;
-       (s >= value
-        && (*s == ' ' || *s == '\t' || *s == '\n'));
-       s--)
-    ;
-  if (!(s >= value))
-    return gpg_error (GPG_ERR_INV_VALUE);  /* Only spaces.  */
-
-  /* Fixme: We should use a dedicated header write functions which
-   * properly wraps the header.  */
-  es_fprintf (ctx->outfp, "Content-Type: %s%s\n\tboundary=\"%s\"\n",
-              value,
-              (*s == ';')? "":";",
-              boundary);
-  return 0;
+  es_fprintf (ctx->outfp, "%s: ", name);
+
+  /* Note that add_header made sure that VALUE does not end with a LF.
+   * Thus we can assume that a LF is followed by non-whitespace.  */
+  for (s = value; *s; s++)
+    {
+      if (*s == '\n')
+        es_fputs ("\r\n\t", ctx->outfp);
+      else
+        es_fputc (*s, ctx->outfp);
+    }
+  if (boundary)
+    {
+      if (s > value && s[-1] != ';')
+        es_fputc (';', ctx->outfp);
+      es_fprintf (ctx->outfp, "\r\n\tboundary=\"%s\"", boundary);
+    }
+
+  es_fputs ("\r\n", ctx->outfp);
+
+  return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
+}
+
+
+static gpg_error_t
+write_gap (mime_maker_t ctx)
+{
+  es_fputs ("\r\n", ctx->outfp);
+  return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
+}
+
+
+static gpg_error_t
+write_boundary (mime_maker_t ctx, const char *boundary, int last)
+{
+  es_fprintf (ctx->outfp, "\r\n--%s%s\r\n", boundary, last?"--":"");
+  return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
+}
+
+
+/* Fixme: Apply required encoding.  */
+static gpg_error_t
+write_body (mime_maker_t ctx, const void *body, size_t bodylen)
+{
+  const char *s;
+
+  for (s = body; bodylen; s++, bodylen--)
+    {
+      if (*s == '\n' && !(s > (const char *)body && s[-1] == '\r'))
+        es_fputc ('\r', ctx->outfp);
+      es_fputc (*s, ctx->outfp);
+    }
+
+  return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
 }
 
 
@@ -572,33 +638,39 @@ write_tree (mime_maker_t ctx, part_t parent, part_t part)
       for (hdr = part->headers; hdr; hdr = hdr->next)
         {
           if (part->child && !strcmp (hdr->name, "Content-Type"))
-            write_ct_with_boundary (ctx, hdr->value, part->boundary);
+            err = write_header (ctx, hdr->name, hdr->value, part->boundary);
           else
-            es_fprintf (ctx->outfp, "%s: %s\n", hdr->name, hdr->value);
+            err = write_header (ctx, hdr->name, hdr->value, NULL);
+          if (err)
+            return err;
         }
-      es_fputc ('\n', ctx->outfp);
+      err = write_gap (ctx);
+      if (err)
+        return err;
       if (part->body)
         {
-          if (es_write (ctx->outfp, part->body, part->bodylen, NULL))
-            return gpg_error_from_syserror ();
+          err = write_body (ctx, part->body, part->bodylen);
+          if (err)
+            return err;
         }
       if (part->child)
         {
           log_assert (part->boundary);
-          if (es_fprintf (ctx->outfp, "\n--%s\n", part->boundary) < 0)
-            return gpg_error_from_syserror ();
-          err = write_tree (ctx, part, part->child);
+          err = write_boundary (ctx, part->boundary, 0);
+          if (!err)
+            err = write_tree (ctx, part, part->child);
+          if (!err)
+            err = write_boundary (ctx, part->boundary, 1);
           if (err)
             return err;
-          if (es_fprintf (ctx->outfp, "\n--%s--\n", part->boundary) < 0)
-            return gpg_error_from_syserror ();
         }
 
       if (part->next)
         {
           log_assert (parent && parent->boundary);
-          if (es_fprintf (ctx->outfp, "\n--%s\n", parent->boundary) < 0)
-            return gpg_error_from_syserror ();
+          err = write_boundary (ctx, parent->boundary, 0);
+          if (err)
+            return err;
         }
     }
   return 0;
diff --git a/tools/mime-maker.h b/tools/mime-maker.h
index 39752db..2fac9c3 100644
--- a/tools/mime-maker.h
+++ b/tools/mime-maker.h
@@ -36,6 +36,7 @@ gpg_error_t mime_maker_add_body (mime_maker_t ctx, const char *string);
 gpg_error_t mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr);
 gpg_error_t mime_maker_add_container (mime_maker_t ctx);
 gpg_error_t mime_maker_end_container (mime_maker_t ctx);
+unsigned int mime_maker_get_partid (mime_maker_t ctx);
 
 gpg_error_t mime_maker_make (mime_maker_t ctx, estream_t fp);
 

commit 95d60c6ce9e8a7a7741553af957978c1f91547c5
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 29 10:20:38 2016 +0200

    tools: Simplify the mime-maker container creation.
    
    * tools/mime-maker.c (struct part_s): Remove field MEDIATYPE.
    (release_parts): Ditto.
    (dump_parts): Print a body line only if tehre is a body.
    (mime_maker_add_header): Check for body or container.
    (mime_maker_add_container): Remove arg MEDIATYPE.  Change all callers.
    (mime_maker_end_container): New.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c
index 660d1bd..143dbc8 100644
--- a/tools/gpg-wks-client.c
+++ b/tools/gpg-wks-client.c
@@ -689,7 +689,7 @@ send_confirmation_response (const char *sender, const char *address,
                                    "protocol=\"application/pgp-encrypted\"");
       if (err)
         goto leave;
-      err = mime_maker_add_container (mime, "multipart/encrypted");
+      err = mime_maker_add_container (mime);
       if (err)
         goto leave;
 
diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c
index 678000c..96e5e05 100644
--- a/tools/gpg-wks-server.c
+++ b/tools/gpg-wks-server.c
@@ -1007,7 +1007,7 @@ send_confirmation_request (server_ctx_t ctx,
                                "protocol=\"application/pgp-encrypted\"");
   if (err)
     goto leave;
-  err = mime_maker_add_container (mime, "multipart/encrypted");
+  err = mime_maker_add_container (mime);
   if (err)
     goto leave;
 
@@ -1214,7 +1214,7 @@ send_congratulation_message (const char *mbox, const char *keyfile)
                                "protocol=\"application/pgp-encrypted\"");
   if (err)
     goto leave;
-  err = mime_maker_add_container (mime, "multipart/encrypted");
+  err = mime_maker_add_container (mime);
   if (err)
     goto leave;
 
diff --git a/tools/mime-maker.c b/tools/mime-maker.c
index 2318891..07783d9 100644
--- a/tools/mime-maker.c
+++ b/tools/mime-maker.c
@@ -48,7 +48,6 @@ struct part_s
 {
   struct part_s *next;  /* Next part in the current container.  */
   struct part_s *child; /* Child container.  */
-  char *mediatype;      /* Mediatype of the container (malloced). */
   char *boundary;       /* Malloced boundary string.  */
   header_t headers;     /* List of headers.  */
   header_t *headers_tail;/* Address of last header in chain.  */
@@ -114,7 +113,6 @@ release_parts (part_t part)
           part->headers = hdrnext;
         }
       release_parts (part->child);
-      xfree (part->mediatype);
       xfree (part->boundary);
       xfree (part->body);
       xfree (part);
@@ -166,7 +164,8 @@ dump_parts (part_t part, int level)
         {
           log_debug ("%*s%s: %s\n", level*2, "", hdr->name, hdr->value);
         }
-      log_debug ("%*s[body %zu bytes]\n", level*2, "", part->bodylen);
+      if (part->body)
+        log_debug ("%*s[body %zu bytes]\n", level*2, "", part->bodylen);
       if (part->child)
         {
           log_debug ("%*s[container]\n", level*2, "");
@@ -378,13 +377,13 @@ mime_maker_add_header (mime_maker_t ctx, const char *name, const char *value)
     return err;
   part = ctx->current_part;
 
-  if (part->body && !parent)
+  if ((part->body || part->child) && !parent)
     {
       /* We already have a body but no parent.  Adding another part is
        * thus not possible.  */
       return gpg_error (GPG_ERR_CONFLICT);
     }
-  if (part->body)
+  if (part->body || part->child)
     {
       /* We already have a body and there is a parent.  We now append
        * a new part to the current container.  */
@@ -474,61 +473,36 @@ mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr)
 }
 
 
-/* Add a new MIME container.  The caller needs to provide the media
- * and media-subtype in MEDIATYPE.  If MEDIATYPE is NULL
- * "multipart/mixed" is assumed.  This function will then add a
- * Content-Type header with that media type and an approriate boundary
- * string to the parent part.  */
+/* Add a new MIME container.  A container can be used instead of a
+ * body.  */
 gpg_error_t
-mime_maker_add_container (mime_maker_t ctx, const char *mediatype)
+mime_maker_add_container (mime_maker_t ctx)
 {
   gpg_error_t err;
   part_t part;
 
-  if (!mediatype)
-    mediatype = "multipart/mixed";
-
   err = ensure_part (ctx, NULL);
   if (err)
     return err;
   part = ctx->current_part;
+
   if (part->body)
     return gpg_error (GPG_ERR_CONFLICT); /* There is already a body. */
-  if (part->child || part->mediatype || part->boundary)
+  if (part->child || part->boundary)
     return gpg_error (GPG_ERR_CONFLICT); /* There is already a container. */
 
-  /* If a content type has not yet been set, do it now.  The boundary
-   * will be added while writing the headers.  */
-  if (!have_header (ctx->mail, "Content-Type"))
-    {
-      err = add_header (ctx->mail, "Content-Type", mediatype);
-      if (err)
-        return err;
-    }
-
   /* Create a child node.  */
   part->child = xtrycalloc (1, sizeof *part->child);
   if (!part->child)
     return gpg_error_from_syserror ();
   part->child->headers_tail = &part->child->headers;
 
-  part->mediatype = xtrystrdup (mediatype);
-  if (!part->mediatype)
-    {
-      err = gpg_error_from_syserror ();
-      xfree (part->child);
-      part->child = NULL;
-      return err;
-    }
-
   part->boundary = generate_boundary (ctx);
   if (!part->boundary)
     {
       err = gpg_error_from_syserror ();
       xfree (part->child);
       part->child = NULL;
-      xfree (part->mediatype);
-      part->mediatype = NULL;
       return err;
     }
 
@@ -539,6 +513,25 @@ mime_maker_add_container (mime_maker_t ctx, const char *mediatype)
 }
 
 
+/* Finish the current container.  */
+gpg_error_t
+mime_maker_end_container (mime_maker_t ctx)
+{
+  gpg_error_t err;
+  part_t parent;
+
+  err = ensure_part (ctx, &parent);
+  if (err)
+    return err;
+  if (!parent)
+    return gpg_error (GPG_ERR_CONFLICT); /* No container.  */
+  while (parent->next)
+    parent = parent->next;
+  ctx->current_part = parent;
+  return 0;
+}
+
+
 /* Write the Content-Type header with the boundary value.  */
 static gpg_error_t
 write_ct_with_boundary (mime_maker_t ctx,
@@ -647,7 +640,7 @@ add_missing_headers (mime_maker_t ctx)
 }
 
 
-/* Create message from the tree MIME and write it to FP.  Noet that
+/* Create message from the tree MIME and write it to FP.  Note that
  * the output uses only a LF and a later called sendmail(1) is
  * expected to convert them to network line endings.  */
 gpg_error_t
diff --git a/tools/mime-maker.h b/tools/mime-maker.h
index b21f7dd..39752db 100644
--- a/tools/mime-maker.h
+++ b/tools/mime-maker.h
@@ -34,7 +34,8 @@ gpg_error_t mime_maker_add_header (mime_maker_t ctx,
                                    const char *name, const char *value);
 gpg_error_t mime_maker_add_body (mime_maker_t ctx, const char *string);
 gpg_error_t mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr);
-gpg_error_t mime_maker_add_container (mime_maker_t ctx, const char *mediatype);
+gpg_error_t mime_maker_add_container (mime_maker_t ctx);
+gpg_error_t mime_maker_end_container (mime_maker_t ctx);
 
 gpg_error_t mime_maker_make (mime_maker_t ctx, estream_t fp);
 

commit 4ac138c84d0f344ca9442f90c96f0e1f76062a4a
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Sep 29 08:11:32 2016 +0200

    tools: Give mime parser callbacks access to the rfc822 parser.
    
    * tools/mime-parser.c (mime_parser_context_s): Add field MSG.
    (parse_message_cb): Set it.
    (mime_parser_rfc822parser): New.
    * tools/mime-parser.h: Declare rfc822parse_t for the new prototype.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/mime-parser.c b/tools/mime-parser.c
index 7ac3c69..0ca5452 100644
--- a/tools/mime-parser.c
+++ b/tools/mime-parser.c
@@ -64,6 +64,9 @@ struct mime_parser_context_s
   /* The callback to collect a signature.  */
   gpg_error_t (*collect_signature) (void *cookie, const char *data);
 
+  /* The RFC822 parser context is stored here during callbacks.  */
+  rfc822parse_t msg;
+
   /* Helper to convey error codes from user callbacks.  */
   gpg_error_t err;
 
@@ -189,6 +192,9 @@ parse_message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
   const char *s;
   int rc = 0;
 
+  /* Make the RFC822 parser context availabale for callbacks.  */
+  ctx->msg = msg;
+
   if (ctx->debug)
     show_message_parser_event (event);
 
@@ -475,6 +481,8 @@ parse_message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
         }
     }
 
+  ctx->msg = NULL;
+
   return rc;
 }
 
@@ -599,6 +607,15 @@ mime_parser_set_collect_signature (mime_parser_t ctx,
 }
 
 
+/* Return the RFC888 parser context.  This is only available inside a
+ * callback.  */
+rfc822parse_t
+mime_parser_rfc822parser (mime_parser_t ctx)
+{
+  return ctx->msg;
+}
+
+
 /* Read and parse a message from FP and call the appropriate
  * callbacks.  */
 gpg_error_t
diff --git a/tools/mime-parser.h b/tools/mime-parser.h
index ab0d792..b217a2c 100644
--- a/tools/mime-parser.h
+++ b/tools/mime-parser.h
@@ -48,5 +48,12 @@ void mime_parser_set_collect_signature (mime_parser_t ctx,
 gpg_error_t mime_parser_parse (mime_parser_t ctx, estream_t fp);
 
 
+/* Duplicated declaration of the RFC822 parser context. */
+struct rfc822parse_context;
+typedef struct rfc822parse_context *rfc822parse_t;
+
+rfc822parse_t mime_parser_rfc822parser (mime_parser_t ctx);
+
+
 
 #endif /*GNUPG_MIME_PARSER_H*/

-----------------------------------------------------------------------

Summary of changes:
 tools/gpg-wks-client.c | 149 +++++++++++++++++++++++++--
 tools/gpg-wks-server.c | 241 ++++++++++++++++++++++++++++++++++++-------
 tools/gpg-wks.h        |  13 ++-
 tools/mime-maker.c     | 272 ++++++++++++++++++++++++++++++++++++-------------
 tools/mime-maker.h     |   6 +-
 tools/mime-parser.c    |  75 ++++++++++----
 tools/mime-parser.h    |   7 ++
 tools/wks-receive.c    |  75 +++++++++++---
 8 files changed, 688 insertions(+), 150 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list