Fix Windows port (spawn and assuan engine).
[gpgme.git] / src / gpgme.c
index 2372a06..7feb3be 100644 (file)
@@ -27,7 +27,9 @@
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
+#ifdef HAVE_LOCALE_H
 #include <locale.h>
+#endif
 
 #include "util.h"
 #include "context.h"
@@ -45,6 +47,10 @@ static char *def_lc_messages;
 \f
 gpgme_error_t _gpgme_selftest = GPG_ERR_NOT_OPERATIONAL;
 
+/* Protects all reference counters in result structures.  All other
+   accesses to a result structure are read only.  */
+DEFINE_STATIC_LOCK (result_ref_lock);
+
 \f
 /* Create a new context as an environment for GPGME crypto
    operations.  */
@@ -73,6 +79,7 @@ gpgme_new (gpgme_ctx_t *r_ctx)
   ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL;
   ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
   ctx->protocol = GPGME_PROTOCOL_OpenPGP;
+  ctx->sub_protocol = GPGME_PROTOCOL_DEFAULT;
   _gpgme_fd_table_init (&ctx->fdt);
 
   LOCK (def_lc_lock);
@@ -114,17 +121,32 @@ gpgme_new (gpgme_ctx_t *r_ctx)
 
 
 gpgme_error_t
-_gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err)
+_gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err,
+                       gpg_error_t op_err)
 {
   gpgme_error_t err;
-  TRACE_BEG1 (DEBUG_CTX, "_gpgme_cancel_with_err", ctx, "ctx_err=%i",
-             ctx_err);
+  struct gpgme_io_event_done_data data;
 
-  err = _gpgme_engine_cancel (ctx->engine);
-  if (err)
-    return TRACE_ERR (err);
+  TRACE_BEG2 (DEBUG_CTX, "_gpgme_cancel_with_err", ctx, "ctx_err=%i, op_err=%i",
+             ctx_err, op_err);
+
+  if (ctx_err)
+    {
+      err = _gpgme_engine_cancel (ctx->engine);
+      if (err)
+       return TRACE_ERR (err);
+    }
+  else
+    {
+      err = _gpgme_engine_cancel_op (ctx->engine);
+      if (err)
+       return TRACE_ERR (err);
+    }
+
+  data.err = ctx_err;
+  data.op_err = op_err;
 
-  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &ctx_err);
+  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &data);
 
   return TRACE_ERR (0);
 }
@@ -134,7 +156,13 @@ _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err)
 gpgme_error_t
 gpgme_cancel (gpgme_ctx_t ctx)
 {
-  return _gpgme_cancel_with_err (ctx, gpg_error (GPG_ERR_CANCELED));
+  gpg_error_t err;
+
+  TRACE_BEG (DEBUG_CTX, "gpgme_cancel", ctx);
+
+  err = _gpgme_cancel_with_err (ctx, gpg_error (GPG_ERR_CANCELED), 0);
+
+  return TRACE_ERR (err);
 }
 
 
@@ -161,8 +189,8 @@ gpgme_release (gpgme_ctx_t ctx)
   _gpgme_engine_release (ctx->engine);
   _gpgme_fd_table_deinit (&ctx->fdt);
   _gpgme_release_result (ctx);
-  gpgme_signers_clear (ctx);
-  gpgme_sig_notation_clear (ctx);
+  _gpgme_signers_clear (ctx);
+  _gpgme_sig_notation_clear (ctx);
   if (ctx->signers)
     free (ctx->signers);
   if (ctx->lc_ctype)
@@ -178,29 +206,44 @@ gpgme_release (gpgme_ctx_t ctx)
 void
 gpgme_result_ref (void *result)
 {
-  struct ctx_op_data *data = result - sizeof (struct ctx_op_data);
+  struct ctx_op_data *data;
 
   if (! result)
     return;
 
+  data = (void*)((char*)result - sizeof (struct ctx_op_data));
+
+  assert (data->magic == CTX_OP_DATA_MAGIC);
+
+  LOCK (result_ref_lock);
   data->references++;
+  UNLOCK (result_ref_lock);
 }
 
 
 void
 gpgme_result_unref (void *result)
 {
-  struct ctx_op_data *data = result - sizeof (struct ctx_op_data);
+  struct ctx_op_data *data;
 
   if (! result)
     return;
 
-  if (--data->references == 0)
+  data = (void*)((char*)result - sizeof (struct ctx_op_data));
+
+  assert (data->magic == CTX_OP_DATA_MAGIC);
+
+  LOCK (result_ref_lock);
+  if (--data->references)
     {
-      if (data->cleanup)
-       (*data->cleanup) (data->hook);
-      free (data);
+      UNLOCK (result_ref_lock);
+      return;
     }
+  UNLOCK (result_ref_lock);
+
+  if (data->cleanup)
+    (*data->cleanup) (data->hook);
+  free (data);
 }
 
 
@@ -225,11 +268,14 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
 {
   TRACE_BEG2 (DEBUG_CTX, "gpgme_set_protocol", ctx, "protocol=%i (%s)",
              protocol, gpgme_get_protocol_name (protocol)
-             ? gpgme_get_protocol_name (protocol) : "unknown");
+             ? gpgme_get_protocol_name (protocol) : "invalid");
 
   if (protocol != GPGME_PROTOCOL_OpenPGP
       && protocol != GPGME_PROTOCOL_CMS
-      && protocol != GPGME_PROTOCOL_ASSUAN)
+      && protocol != GPGME_PROTOCOL_GPGCONF
+      && protocol != GPGME_PROTOCOL_ASSUAN
+      && protocol != GPGME_PROTOCOL_G13
+      && protocol != GPGME_PROTOCOL_UISERVER)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
   if (ctx->protocol != protocol)
@@ -254,11 +300,33 @@ gpgme_get_protocol (gpgme_ctx_t ctx)
   TRACE2 (DEBUG_CTX, "gpgme_get_protocol", ctx,
          "ctx->protocol=%i (%s)", ctx->protocol,
          gpgme_get_protocol_name (ctx->protocol)
-         ? gpgme_get_protocol_name (ctx->protocol) : "unknown");
+         ? gpgme_get_protocol_name (ctx->protocol) : "invalid");
   return ctx->protocol;
 }
 
 
+gpgme_error_t
+gpgme_set_sub_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
+{
+  TRACE2 (DEBUG_CTX, "gpgme_set_sub_protocol", ctx, "protocol=%i (%s)",
+         protocol, gpgme_get_protocol_name (protocol)
+         ? gpgme_get_protocol_name (protocol) : "invalid");
+  ctx->sub_protocol = protocol;
+  return 0;
+}
+
+
+gpgme_error_t
+gpgme_get_sub_protocol (gpgme_ctx_t ctx)
+{
+  TRACE2 (DEBUG_CTX, "gpgme_get_sub_protocol", ctx,
+         "ctx->sub_protocol=%i (%s)", ctx->sub_protocol,
+         gpgme_get_protocol_name (ctx->sub_protocol)
+         ? gpgme_get_protocol_name (ctx->sub_protocol) : "invalid");
+  return ctx->sub_protocol;
+}
+
+
 const char *
 gpgme_get_protocol_name (gpgme_protocol_t protocol)
 {
@@ -270,9 +338,21 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol)
     case GPGME_PROTOCOL_CMS:
       return "CMS";
 
+    case GPGME_PROTOCOL_GPGCONF:
+      return "GPGCONF";
+
     case GPGME_PROTOCOL_ASSUAN:
       return "Assuan";
 
+    case GPGME_PROTOCOL_G13:
+      return "G13";
+
+    case GPGME_PROTOCOL_UISERVER:
+      return "UIServer";
+
+    case GPGME_PROTOCOL_DEFAULT:
+      return "default";
+
     case GPGME_PROTOCOL_UNKNOWN:
       return "unknown";
 
@@ -463,10 +543,12 @@ ssize_t
 gpgme_io_read (int fd, void *buffer, size_t count)
 {
   int ret;
+  TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_read", fd,
+             "buffer=%p, count=%u", buffer, count);
 
   ret = _gpgme_io_read (fd, buffer, count);
 
-  return ret;
+  return TRACE_SYSRES (ret);
 }
 
 
@@ -477,10 +559,12 @@ ssize_t
 gpgme_io_write (int fd, const void *buffer, size_t count)
 {
   int ret;
+  TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_write", fd,
+             "buffer=%p, count=%u", buffer, count);
 
   ret = _gpgme_io_write (fd, buffer, count);
 
-  return ret;
+  return TRACE_SYSRES (ret);
 }
 
 
@@ -518,7 +602,9 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
         failed = 1;                                            \
     }
 
+#ifdef LC_CTYPE
   PREPARE_ONE_LOCALE (ctype, CTYPE);
+#endif
 #ifdef LC_MESSAGES
   PREPARE_ONE_LOCALE (messages, MESSAGES);
 #endif
@@ -554,7 +640,9 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
 
   if (!ctx)
     LOCK (def_lc_lock);
+#ifdef LC_CTYPE
   SET_ONE_LOCALE (ctype, CTYPE);
+#endif
 #ifdef LC_MESSAGES
   SET_ONE_LOCALE (messages, MESSAGES);
 #endif
@@ -606,10 +694,9 @@ gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,
 \f
 /* Clear all notation data from the context.  */
 void
-gpgme_sig_notation_clear (gpgme_ctx_t ctx)
+_gpgme_sig_notation_clear (gpgme_ctx_t ctx)
 {
   gpgme_sig_notation_t notation;
-  TRACE (DEBUG_CTX, "gpgme_sig_notation_clear", ctx);
 
   if (!ctx)
     return;
@@ -624,6 +711,13 @@ gpgme_sig_notation_clear (gpgme_ctx_t ctx)
   ctx->sig_notations = NULL;
 }
 
+void
+gpgme_sig_notation_clear (gpgme_ctx_t ctx)
+{
+  TRACE (DEBUG_CTX, "gpgme_sig_notation_clear", ctx);
+  _gpgme_sig_notation_clear (ctx);
+}
+
 
 /* Add the human-readable notation data with name NAME and value VALUE
    to the context CTX, using the flags FLAGS.  If NAME is NULL, then
@@ -704,6 +798,12 @@ gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
     case GPGME_PK_ELG:
       return "ELG";
 
+    case GPGME_PK_ECDSA:
+      return "ECDSA";
+
+    case GPGME_PK_ECDH:
+      return "ECDH";
+
     default:
       return NULL;
     }