2009-11-03 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Tue, 3 Nov 2009 19:15:35 +0000 (19:15 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Tue, 3 Nov 2009 19:15:35 +0000 (19:15 +0000)
* Makefile.am (main_sources): Change g13.c to vfs-mount.c.  Add
vfs-create.c
* vfs-create.c: New file.
* g13.c: Renamed to ...
* vfs-mount.c: ... this new file.
* gpgme.h.in (gpgme_op_vfs_create): New prototype.
* gpgme.def, libgpgme.vers: Add gpgme_op_vfs_create.
* gpgme-tool.c (gt_vfs_create, cmd_vfs_create): New functions.
(register_commands): Add VFS_CREATE and CREAET.

src/ChangeLog
src/Makefile.am
src/gpgme-tool.c
src/gpgme.def
src/gpgme.h.in
src/libgpgme.vers
src/vfs-create.c [new file with mode: 0644]
src/vfs-mount.c [moved from src/g13.c with 97% similarity]

index 8c3689e7c2df9b46e8fe7efd8e061d1267febd85..bcfaa729d5d2b6eeb575d76652e0c4557bfc9436 100644 (file)
@@ -1,3 +1,15 @@
+2009-11-03  Marcus Brinkmann  <marcus@g10code.de>
+
+       * Makefile.am (main_sources): Change g13.c to vfs-mount.c.  Add
+       vfs-create.c
+       * vfs-create.c: New file.
+       * g13.c: Renamed to ...
+       * vfs-mount.c: ... this new file.
+       * gpgme.h.in (gpgme_op_vfs_create): New prototype.
+       * gpgme.def, libgpgme.vers: Add gpgme_op_vfs_create.
+       * gpgme-tool.c (gt_vfs_create, cmd_vfs_create): New functions.
+       (register_commands): Add VFS_CREATE and CREAET.
+
 2009-11-02  Marcus Brinkmann  <marcus@g10code.de>
 
        * debug.h (_gpgme_debug_buffer): Make TAG argument const const.
index 677a89691f9f0321266604cc85c5f0b1288f716f..b1d93d36f279c0d7301135c8535a8752ca5652de 100644 (file)
@@ -111,7 +111,7 @@ main_sources =                                                              \
        opassuan.c                                                      \
        engine.h engine-backend.h engine.c engine-gpg.c status-table.h  \
        $(gpgsm_components) $(assuan_components) $(gpgconf_components)  \
-       $(g13_components) g13.c                                         \
+       $(g13_components) vfs-mount.c vfs-create.c                      \
        gpgconf.c                                                       \
        sema.h priv-io.h $(system_components) dirinfo.c                 \
        debug.c debug.h gpgme.c version.c error.c
index e4948e28b6da0cf056bed2eaf41cf62347221857..7a41be0801a37e90c8a0009cd8a05fe6f4353468 100644 (file)
@@ -483,6 +483,7 @@ typedef enum status
     STATUS_TEXTMODE,
     STATUS_INCLUDE_CERTS,
     STATUS_KEYLIST_MODE,
+    STATUS_RECIPIENT,
     STATUS_ENCRYPT_RESULT
   } status_t;
 
@@ -495,6 +496,7 @@ const char *status_string[] =
     "TEXTMODE",
     "INCLUDE_CERTS",
     "KEYLIST_MODE",
+    "RECIPIENT",
     "ENCRYPT_RESULT"
   };
 
@@ -574,7 +576,88 @@ gt_signers_clear (gpgme_tool_t gt)
 
 
 gpg_error_t
-gt_recipients_add (gpgme_tool_t gt, const char *fpr)
+gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
+{
+  gpgme_ctx_t ctx;
+  gpgme_ctx_t listctx;
+  gpgme_error_t err;
+  gpgme_key_t key;
+
+  if (!gt || !r_key || !pattern)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  
+  ctx = gt->ctx;
+
+  err = gpgme_new (&listctx);
+  if (err)
+    return err;
+
+  {
+    gpgme_protocol_t proto;
+    gpgme_engine_info_t info;
+
+    /* Clone the relevant state.  */
+    proto = gpgme_get_protocol (ctx);
+    /* The g13 protocol does not allow keylisting, we need to choose
+       something else.  */
+    if (proto == GPGME_PROTOCOL_G13)
+      proto = GPGME_PROTOCOL_OpenPGP;
+
+    gpgme_set_protocol (listctx, proto);
+    gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
+    info = gpgme_ctx_get_engine_info (ctx);
+    while (info && info->protocol != proto)
+      info = info->next;
+    if (info)
+      gpgme_ctx_set_engine_info (listctx, proto,
+                                info->file_name, info->home_dir);
+  }
+
+  err = gpgme_op_keylist_start (listctx, pattern, 0);
+  if (!err)
+    err = gpgme_op_keylist_next (listctx, r_key);
+  if (!err)
+    {
+    try_next_key:
+      err = gpgme_op_keylist_next (listctx, &key);
+      if (gpgme_err_code (err) == GPG_ERR_EOF)
+       err = 0;
+      else
+       {
+          if (!err
+              && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
+              && key && key->subkeys && key->subkeys->fpr
+              && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
+            {
+              /* The fingerprint is identical.  We assume that this is
+                 the same key and don't mark it as an ambiguous.  This
+                 problem may occur with corrupted keyrings and has
+                 been noticed often with gpgsm.  In fact gpgsm uses a
+                 similar hack to sort out such duplicates but it can't
+                 do that while listing keys.  */
+              gpgme_key_unref (key);
+              goto try_next_key;
+            }
+         if (!err)
+           {
+             gpgme_key_unref (key);
+             err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+           }
+         gpgme_key_unref (*r_key);
+       }
+    }
+  gpgme_release (listctx);
+  
+  if (! err)
+    gt_write_status (gt, STATUS_RECIPIENT, 
+                    ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ? 
+                    (*r_key)->subkeys->fpr : "invalid", NULL);
+  return err;
+}
+
+
+gpg_error_t
+gt_recipients_add (gpgme_tool_t gt, const char *pattern)
 {
   gpg_error_t err;
   gpgme_key_t key;
@@ -582,7 +665,7 @@ gt_recipients_add (gpgme_tool_t gt, const char *fpr)
   if (gt->recipients_nr >= MAX_RECIPIENTS)
     return gpg_error_from_errno (ENOMEM);
 
-  err = gpgme_get_key (gt->ctx, fpr, &key, 0);
+  err = gt_get_key (gt, pattern, &key);
   if (err)
     return err;
 
@@ -962,6 +1045,18 @@ gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
 }
 
 
+gpg_error_t
+gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
+{
+  gpg_error_t err;
+  gpg_error_t op_err;
+  err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
+                            flags, &op_err);
+  gt_recipients_clear (gt);
+  return err || op_err;
+}
+
+
 // TODO
 #define GT_RESULT_ENCRYPT 0x1
 #define GT_RESULT_DECRYPT 0x2
@@ -1742,6 +1837,27 @@ cmd_vfs_mount (assuan_context_t ctx, char *line)
 }
 
 
+static gpg_error_t
+cmd_vfs_create (assuan_context_t ctx, char *line)
+{
+  struct server *server = assuan_get_pointer (ctx);
+  gpg_error_t err;
+  char *end;
+
+  end = strchr (line, ' ');
+  if (end)
+    {
+      *(end++) = '\0';
+      while (*end == ' ')
+       end++;
+    }
+
+  err = gt_vfs_create (server->gt, line, 0);
+
+  return err;
+}
+
+
 static gpg_error_t
 cmd_result (assuan_context_t ctx, char *line)
 {
@@ -1835,6 +1951,8 @@ register_commands (assuan_context_t ctx)
     // TODO: ASSUAN
     { "VFS_MOUNT", cmd_vfs_mount },
     { "MOUNT", cmd_vfs_mount },
+    { "VFS_CREATE", cmd_vfs_create },
+    { "CREATE", cmd_vfs_create },
     // TODO: GPGCONF
     { "RESULT", cmd_result },
     { "STRERROR", cmd_strerror },
index 6d223f4d2c3503464dea58739d10215f97686713..816da31886550016536cd88ff98a5e10c11beaca 100644 (file)
@@ -190,6 +190,7 @@ EXPORTS
     gpgme_wait_ext                       @145
     gpgme_op_vfs_mount_result            @146
     gpgme_op_vfs_mount                   @147
+    gpgme_op_vfs_create                          @148
 
 ; END
 
index 42b9237f7fd4d617f052751ffd6aaf00e3971ee8..f0a61d79796924c205823b3b659556865ce25e63 100644 (file)
@@ -1808,9 +1808,13 @@ gpgme_vfs_mount_result_t gpgme_op_vfs_mount_result (gpgme_ctx_t ctx);
    or destroyed.  Transmission errors are returned directly,
    operational errors are returned in OP_ERR.  */
 gpgme_error_t gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,
-                                 const char *mount_dir, int flags,
+                                 const char *mount_dir, unsigned int flags,
                                  gpgme_error_t *op_err);
 
+gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                                  const char *container_file,
+                                  unsigned int flags, gpgme_error_t *op_err);
+
 \f
 /* Interface to gpgconf(1).  */
 
index 9989c75b2ce6138d10ec9a0c5be6915f75a3da4f..24107d482a0021ef09d765ad067541d1eeaf2baf 100644 (file)
@@ -71,6 +71,8 @@ GPGME_1.1 {
 
     gpgme_op_vfs_mount_result;
     gpgme_op_vfs_mount;
+    gpgme_op_vfs_create;
+
 };
 
 
diff --git a/src/vfs-create.c b/src/vfs-create.c
new file mode 100644 (file)
index 0000000..a965a96
--- /dev/null
@@ -0,0 +1,193 @@
+/* vfs-create.c - vfs create support in GPGME
+   Copyright (C) 2009 g10 Code GmbH
+
+   This file is part of GPGME.
+   GPGME is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+   
+   GPGME is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+   
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+#include "util.h"
+
+static gpgme_error_t
+vfs_start (gpgme_ctx_t ctx, int synchronous,
+          const char *command,
+          gpgme_assuan_data_cb_t data_cb,
+          void *data_cb_value,
+          gpgme_assuan_inquire_cb_t inq_cb,
+          void *inq_cb_value,
+          gpgme_assuan_status_cb_t status_cb,
+          void *status_cb_value)
+{
+  gpgme_error_t err;
+
+  if (!command || !*command)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* The flag value 256 is used to suppress an engine reset.  This is
+     required to keep the connection running.  */
+  err = _gpgme_op_reset (ctx, ((synchronous & 255) | 256));
+  if (err)
+    return err;
+
+  return _gpgme_engine_op_assuan_transact (ctx->engine, command,
+                                          data_cb, data_cb_value,
+                                          inq_cb, inq_cb_value,
+                                          status_cb, status_cb_value);
+}
+
+
+
+/* XXXX.  This is the asynchronous variant. */
+static gpgme_error_t
+gpgme_op_vfs_transact_start (gpgme_ctx_t ctx, 
+                            const char *command,
+                            gpgme_assuan_data_cb_t data_cb,
+                            void *data_cb_value,
+                            gpgme_assuan_inquire_cb_t inq_cb,
+                            void *inq_cb_value,
+                            gpgme_assuan_status_cb_t status_cb,
+                            void *status_cb_value)
+{
+  return vfs_start (ctx, 0, command, data_cb, data_cb_value,
+                   inq_cb, inq_cb_value, status_cb, status_cb_value);
+}
+
+
+/* XXXX.  This is the synchronous variant. */
+static gpgme_error_t
+gpgme_op_vfs_transact (gpgme_ctx_t ctx,
+                      const char *command,
+                      gpgme_assuan_data_cb_t data_cb,
+                      void *data_cb_value,
+                      gpgme_assuan_inquire_cb_t inq_cb,
+                      void *inq_cb_value,
+                      gpgme_assuan_status_cb_t status_cb,
+                      void *status_cb_value,
+                      gpgme_error_t *op_err)
+{
+  gpgme_error_t err;
+  
+  err = vfs_start (ctx, 1, command, data_cb, data_cb_value,
+                  inq_cb, inq_cb_value, status_cb, status_cb_value);
+  if (!err)
+    err = _gpgme_wait_one_ext (ctx, op_err);
+  return err;
+}
+
+\f
+/* The actual exported interface follows.  */
+
+/* The container is automatically uncreateed when the context is reset
+   or destroyed.  This is a synchronous convenience interface, which
+   automatically returns an operation error if there is no
+   transmission error.  */
+static gpgme_error_t
+_gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                     const char *container_file, unsigned int flags,
+                     gpgme_error_t *op_err)
+{
+  gpg_error_t err;
+  char *cmd;
+  char *container_file_esc = NULL;
+  int i;
+
+  /* We want to encourage people to check error values, so not getting
+     them is discouraged here.  Also makes our code easier.  */
+  if (! op_err)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  err = _gpgme_encode_percent_string (container_file, &container_file_esc, 0);
+  if (err)
+    return err;
+
+  i = 0;
+  while (!err && recp[i])
+    {
+      if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
+       {
+         free (container_file_esc);
+         return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+       }
+
+      if (asprintf (&cmd, "RECIPIENT %s", recp[i]->subkeys->fpr) < 0)
+       {
+         err = gpg_error_from_syserror ();
+         free (container_file_esc);
+         return err;
+       }
+      
+      err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL,
+                                  NULL, NULL, op_err);
+      free (cmd);
+      if (err || *op_err)
+       {
+         free (container_file_esc);
+         return err;
+       }
+      recp++;
+    }
+
+  if (asprintf (&cmd, "CREATE -- %s", container_file_esc) < 0)
+    {
+      err = gpg_error_from_syserror ();
+      free (container_file_esc);
+      return err;
+    }
+  free (container_file_esc);
+    
+  err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL,
+                              NULL, NULL, op_err);
+  free (cmd);
+
+  return err;
+}
+
+
+gpgme_error_t
+gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                     const char *container_file, unsigned int flags,
+                     gpgme_error_t *op_err)
+{
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_vfs_create", ctx,
+             "container_file=%s, flags=0x%x, op_err=%p",
+             container_file, flags, op_err);
+
+  if (_gpgme_debug_trace () && recp)
+    {
+      int i = 0;
+
+      while (recp[i])
+       {
+         TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+                     (recp[i]->subkeys && recp[i]->subkeys->fpr) ? 
+                     recp[i]->subkeys->fpr : "invalid");
+         i++;
+       }
+    }
+
+  return TRACE_ERR (_gpgme_op_vfs_create (ctx, recp, container_file,
+                                         flags, op_err));
+}
+
similarity index 97%
rename from src/g13.c
rename to src/vfs-mount.c
index a2ab675e2d0c8a92ddfccbda62cedda86aa4c409..3c0b6f2492e37054c5452feb09849b97e614916d 100644 (file)
--- a/src/g13.c
@@ -1,4 +1,4 @@
-/* g13.c - g13 support in GPGME
+/* vfs-mount.c - vfs mount support in GPGME
    Copyright (C) 2009 g10 Code GmbH
 
    This file is part of GPGME.
@@ -198,7 +198,8 @@ _gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,
 
 gpgme_error_t
 gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,
-                    const char *mount_dir, int flags, gpgme_error_t *op_err)
+                   const char *mount_dir, unsigned int flags,
+                   gpgme_error_t *op_err)
 {
   TRACE_BEG4 (DEBUG_CTX, "gpgme_op_vfs_mount", ctx,
              "container=%s, mount_dir=%s, flags=0x%x, op_err=%p",