2008-06-27 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / gpgme.c
index d4637f0..0f3527a 100644 (file)
-/* gpgme.c -  GnuPG Made Easy
- *     Copyright (C) 2000 Werner Koch (dd9jn)
- *      Copyright (C) 2001, 2002 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 General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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
- */
+/* gpgme.c - GnuPG Made Easy.
+   Copyright (C) 2000 Werner Koch (dd9jn)
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
+#include <locale.h>
 
 #include "util.h"
 #include "context.h"
 #include "ops.h"
+#include "wait.h"
+#include "debug.h"
+
+\f
+/* The default locale.  */
+DEFINE_STATIC_LOCK (def_lc_lock);
+static char *def_lc_ctype;
+static char *def_lc_messages;
 
-/**
- * gpgme_new:
- * @r_ctx: Returns the new context
- * 
- * Create a new context to be used with most of the other GPGME
- * functions.  Use gpgme_release_context() to release all resources
- *
- * Return value: An error code 
- **/
-GpgmeError
-gpgme_new (GpgmeCtx *r_ctx)
+\f
+/* Create a new context as an environment for GPGME crypto
+   operations.  */
+gpgme_error_t
+gpgme_new (gpgme_ctx_t *r_ctx)
 {
-  GpgmeCtx ctx;
+  gpgme_ctx_t ctx;
+  TRACE_BEG (DEBUG_CTX, "gpgme_new", r_ctx);
 
-  if (!r_ctx)
-    return mk_error (Invalid_Value);
-  *r_ctx = 0;
-  ctx = xtrycalloc (1, sizeof *ctx);
+  ctx = calloc (1, sizeof *ctx);
   if (!ctx)
-    return mk_error (Out_Of_Core);
-  ctx->verbosity = 1;
+    return TRACE_ERR (gpg_error_from_errno (errno));
+
+  INIT_LOCK (ctx->lock);
+  
+  _gpgme_engine_info_copy (&ctx->engine_info);
+  if (!ctx->engine_info)
+    {
+      free (ctx);
+      return TRACE_ERR (gpg_error_from_errno (errno));
+    }
+
+  ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL;
+  ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
+  ctx->protocol = GPGME_PROTOCOL_OpenPGP;
+  _gpgme_fd_table_init (&ctx->fdt);
+
+  LOCK (def_lc_lock);
+  if (def_lc_ctype)
+    {
+      ctx->lc_ctype = strdup (def_lc_ctype);
+      if (!ctx->lc_ctype)
+       {
+         UNLOCK (def_lc_lock);
+         _gpgme_engine_info_release (ctx->engine_info);
+         free (ctx);
+         return TRACE_ERR (gpg_error_from_errno (errno));
+       }
+    }
+  else
+    def_lc_ctype = NULL;
+
+  if (def_lc_messages)
+    {
+      ctx->lc_messages = strdup (def_lc_messages);
+      if (!ctx->lc_messages)
+       {
+         UNLOCK (def_lc_lock);
+         if (ctx->lc_ctype)
+           free (ctx->lc_ctype);
+         _gpgme_engine_info_release (ctx->engine_info);
+         free (ctx);
+         return TRACE_ERR (gpg_error_from_errno (errno));
+       }
+    }
+  else
+    def_lc_messages = NULL;
+  UNLOCK (def_lc_lock);
+
   *r_ctx = ctx;
 
-  return 0;
+  return TRACE_SUC1 ("ctx=%p", ctx);
+}
+
+
+/* Cancel a pending asynchronous operation.  */
+gpgme_error_t
+gpgme_cancel (gpgme_ctx_t ctx)
+{
+  gpgme_error_t err;
+  TRACE_BEG (DEBUG_CTX, "gpgme_cancel", ctx);
+
+  err = _gpgme_engine_cancel (ctx->engine);
+  if (err)
+    return TRACE_ERR (err);
+
+  err = gpg_error (GPG_ERR_CANCELED);
+  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
+
+  return TRACE_ERR (0);
 }
 
-/**
- * gpgme_release:
- * @c: Context to be released. 
- * 
- * Release all resources associated with the given context.
- **/
+
+/* Cancel a pending operation asynchronously.  */
+gpgme_error_t
+gpgme_cancel_async (gpgme_ctx_t ctx)
+{
+  gpgme_error_t err;
+  TRACE_BEG (DEBUG_CTX, "gpgme_cancel_async", ctx);
+
+  LOCK (ctx->lock);
+  ctx->canceled = 1;
+  UNLOCK (ctx->lock);
+
+  return TRACE_ERR (0);
+}
+
+
+/* Release all resources associated with the given context.  */
 void
-gpgme_release (GpgmeCtx ctx)
+gpgme_release (gpgme_ctx_t ctx)
 {
-  if (!ctx)
-    return;
-  _gpgme_engine_release (ctx->engine); 
+  TRACE (DEBUG_CTX, "gpgme_release", ctx);
+
+  _gpgme_engine_release (ctx->engine);
+  _gpgme_fd_table_deinit (&ctx->fdt);
   _gpgme_release_result (ctx);
-  gpgme_key_release (ctx->tmp_key);
-  gpgme_data_release (ctx->help_data_1);
-  gpgme_data_release (ctx->notation);
   gpgme_signers_clear (ctx);
+  gpgme_sig_notation_clear (ctx);
   if (ctx->signers)
-    xfree (ctx->signers);
-  /* FIXME: Release the key_queue.  */
-  xfree (ctx);
+    free (ctx->signers);
+  if (ctx->lc_ctype)
+    free (ctx->lc_ctype);
+  if (ctx->lc_messages)
+    free (ctx->lc_messages);
+  _gpgme_engine_info_release (ctx->engine_info);
+  DESTROY_LOCK (ctx->lock);
+  free (ctx);
 }
 
+
 void
-_gpgme_release_result (GpgmeCtx ctx)
+_gpgme_release_result (gpgme_ctx_t ctx)
 {
-  _gpgme_release_verify_result (ctx->result.verify);
-  _gpgme_release_decrypt_result (ctx->result.decrypt);
-  _gpgme_release_sign_result (ctx->result.sign);
-  _gpgme_release_encrypt_result (ctx->result.encrypt);
-  _gpgme_release_passphrase_result (ctx->result.passphrase);
-  _gpgme_release_import_result (ctx->result.import);
-  _gpgme_release_delete_result (ctx->result.delete);
-  _gpgme_release_genkey_result (ctx->result.genkey);
-  memset (&ctx->result, 0, sizeof (ctx->result));
-  _gpgme_set_op_info (ctx, NULL);
-  ctx->error = 0;
+  struct ctx_op_data *data = ctx->op_data;
+
+  while (data)
+    {
+      struct ctx_op_data *next_data = data->next;
+      if (data->cleanup)
+       (*data->cleanup) (data->hook);
+      free (data);
+      data = next_data;
+    }
+  ctx->op_data = NULL;
 }
 
 
-/**
- * gpgme_cancel:
- * @c: the context
- * 
- * Cancel the current operation.  It is not guaranteed that it will work for
- * all kinds of operations.  It is especially useful in a passphrase callback
- * to stop the system from asking another time for the passphrase.
- **/
-void
-gpgme_cancel (GpgmeCtx ctx)
+gpgme_error_t
+gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
 {
-  return_if_fail (ctx);
+  TRACE_BEG2 (DEBUG_CTX, "gpgme_set_protocol", ctx, "protocol=%i (%s)",
+             protocol, gpgme_get_protocol_name (protocol)
+             ? gpgme_get_protocol_name (protocol) : "unknown");
+
+  if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
-  ctx->cancel = 1;
+  if (ctx->protocol != protocol)
+    {
+      /* Shut down the engine when switching protocols.  */
+      if (ctx->engine)
+       {
+         TRACE_LOG1 ("releasing ctx->engine=%p", ctx->engine);
+         _gpgme_engine_release (ctx->engine);
+         ctx->engine = NULL;
+       }
+
+      ctx->protocol = protocol;
+    }
+  return TRACE_ERR (0);
 }
 
-/**
- * gpgme_get_notation:
- * @c: the context 
- * 
- * If there is notation data available from the last signature check,
- * this function may be used to return this notation data as a string.
- * The string is an XML represantaton of that data embedded in a
- * %&lt;notation&gt; container.
- * 
- * Return value: An XML string or NULL if no notation data is available.
- **/
-char *
-gpgme_get_notation (GpgmeCtx ctx)
+
+gpgme_protocol_t
+gpgme_get_protocol (gpgme_ctx_t ctx)
 {
-  if (!ctx->notation)
-    return NULL;
-  return _gpgme_data_get_as_string (ctx->notation);
+  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");
+  return ctx->protocol;
 }
 
 
-/**
- * gpgme_get_op_info:
- * @c: the context 
- * @reserved: 
- * 
- * Return information about the last information.  The caller has to
- * free the string.  NULL is returned if there is not previous
- * operation available or the operation has not yet finished.
- *
- * Here is a sample information we return:
- * <literal>
- * <![CDATA[
- * <GnupgOperationInfo>
- *   <signature>
- *     <detached/> <!-- or cleartext or standard -->
- *     <algo>17</algo>
- *     <hashalgo>2</hashalgo>
- *     <micalg>pgp-sha1</micalg>
- *     <sigclass>01</sigclass>
- *     <created>9222222</created>
- *     <fpr>121212121212121212</fpr>
- *   </signature>
- * </GnupgOperationInfo>
- * ]]>
- * </literal>
- * Return value: NULL for no info available or an XML string 
- **/
-char *
-gpgme_get_op_info (GpgmeCtx ctx, int reserved)
+const char *
+gpgme_get_protocol_name (gpgme_protocol_t protocol)
 {
-  if (!ctx || reserved)
-    return NULL;  /* Invalid value.  */
-  return _gpgme_data_get_as_string (ctx->op_info);
+  switch (protocol)
+    {
+    case GPGME_PROTOCOL_OpenPGP:
+      return "OpenPGP";
+
+    case GPGME_PROTOCOL_CMS:
+      return "CMS";
+
+    case GPGME_PROTOCOL_UNKNOWN:
+      return "unknown";
+
+    default:
+      return NULL;
+    }
+}
+
+/* Enable or disable the use of an ascii armor for all output.  */
+void
+gpgme_set_armor (gpgme_ctx_t ctx, int use_armor)
+{
+  TRACE2 (DEBUG_CTX, "gpgme_set_armor", ctx, "use_armor=%i (%s)",
+         use_armor, use_armor ? "yes" : "no");
+  ctx->use_armor = use_armor;
 }
 
 
-/*
- * Store the data object with the operation info in the
- * context. Caller should not use that object anymore.  
- */
+/* Return the state of the armor flag.  */
+int
+gpgme_get_armor (gpgme_ctx_t ctx)
+{
+  TRACE2 (DEBUG_CTX, "gpgme_get_armor", ctx, "ctx->use_armor=%i (%s)",
+         ctx->use_armor, ctx->use_armor ? "yes" : "no");
+  return ctx->use_armor;
+}
+
+
+/* Enable or disable the use of the special textmode.  Textmode is for
+  example used for the RFC2015 signatures; note that the updated RFC
+  3156 mandates that the MUA does some preparations so that textmode
+  is not needed anymore.  */
 void
-_gpgme_set_op_info (GpgmeCtx ctx, GpgmeData info)
+gpgme_set_textmode (gpgme_ctx_t ctx, int use_textmode)
 {
-  assert (ctx);
+  TRACE2 (DEBUG_CTX, "gpgme_set_textmode", ctx, "use_textmode=%i (%s)",
+         use_textmode, use_textmode ? "yes" : "no");
+  ctx->use_textmode = use_textmode;
+}
 
-  gpgme_data_release (ctx->op_info); 
-  ctx->op_info = NULL;
+/* Return the state of the textmode flag.  */
+int
+gpgme_get_textmode (gpgme_ctx_t ctx)
+{
+  TRACE2 (DEBUG_CTX, "gpgme_get_textmode", ctx, "ctx->use_textmode=%i (%s)",
+         ctx->use_textmode, ctx->use_textmode ? "yes" : "no");
+  return ctx->use_textmode;
+}
+
+
+/* Set the number of certifications to include in an S/MIME message.
+   The default is GPGME_INCLUDE_CERTS_DEFAULT.  -1 means all certs,
+   and -2 means all certs except the root cert.  */
+void
+gpgme_set_include_certs (gpgme_ctx_t ctx, int nr_of_certs)
+{
+  if (nr_of_certs == GPGME_INCLUDE_CERTS_DEFAULT)
+    ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
+  else if (nr_of_certs < -2)
+    ctx->include_certs = -2;
+  else
+    ctx->include_certs = nr_of_certs;
 
-  if (info)
-    ctx->op_info = info;
+  TRACE2 (DEBUG_CTX, "gpgme_set_include_certs", ctx, "nr_of_certs=%i%s",
+         nr_of_certs, nr_of_certs == ctx->include_certs ? "" : " (-2)");
 }
 
 
-GpgmeError
-gpgme_set_protocol (GpgmeCtx ctx, GpgmeProtocol protocol)
+/* Get the number of certifications to include in an S/MIME
+   message.  */
+int
+gpgme_get_include_certs (gpgme_ctx_t ctx)
 {
-  if (!ctx)
-    return mk_error (Invalid_Value);
-  
-  switch (protocol)
-    {
-    case GPGME_PROTOCOL_OpenPGP:
-      ctx->use_cms = 0;
-      break;
-    case GPGME_PROTOCOL_CMS:
-      ctx->use_cms = 1;
-      break;
-    case GPGME_PROTOCOL_AUTO:
-      return mk_error (Not_Implemented);
-    default:
-      return mk_error (Invalid_Value);
-    }
-  
+  TRACE1 (DEBUG_CTX, "gpgme_get_include_certs", ctx, "ctx->include_certs=%i",
+         ctx->include_certs);
+  return ctx->include_certs;
+}
+
+
+/* This function changes the default behaviour of the keylisting
+   functions.  MODE is a bitwise-OR of the GPGME_KEYLIST_* flags.  The
+   default mode is GPGME_KEYLIST_MODE_LOCAL.  */
+gpgme_error_t
+gpgme_set_keylist_mode (gpgme_ctx_t ctx, gpgme_keylist_mode_t mode)
+{
+  TRACE1 (DEBUG_CTX, "gpgme_set_keylist_mode", ctx, "keylist_mode=0x%x",
+         mode);
+
+  ctx->keylist_mode = mode;
   return 0;
 }
 
+/* This function returns the default behaviour of the keylisting
+   functions.  */
+gpgme_keylist_mode_t
+gpgme_get_keylist_mode (gpgme_ctx_t ctx)
+{
+  TRACE1 (DEBUG_CTX, "gpgme_get_keylist_mode", ctx,
+         "ctx->keylist_mode=0x%x", ctx->keylist_mode);
+  return ctx->keylist_mode;
+}
 
-/**
- * gpgme_set_armor:
- * @ctx: the context 
- * @yes: boolean value to set or clear that flag
- * 
- * Enable or disable the use of an ascii armor for all output.  
- **/
+
+/* This function sets a callback function to be used to pass a
+   passphrase to gpg.  */
 void
-gpgme_set_armor (GpgmeCtx ctx, int yes)
+gpgme_set_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb,
+                        void *cb_value)
 {
-  if (!ctx)
-    return;
-  ctx->use_armor = yes;
+  TRACE2 (DEBUG_CTX, "gpgme_set_passphrase_cb", ctx,
+         "passphrase_cb=%p/%p", cb, cb_value);
+  ctx->passphrase_cb = cb;
+  ctx->passphrase_cb_value = cb_value;
 }
 
 
-/**
- * gpgme_get_armor:
- * @ctx: the context
- * 
- * Return the state of the armor flag which can be changed using
- * gpgme_set_armor().
- * 
- * Return value: Boolean whether armor mode is to be used.
- **/
-int 
-gpgme_get_armor (GpgmeCtx ctx)
+/* This function returns the callback function to be used to pass a
+   passphrase to the crypto engine.  */
+void
+gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *r_cb,
+                        void **r_cb_value)
 {
-  return ctx && ctx->use_armor;
+  TRACE2 (DEBUG_CTX, "gpgme_get_passphrase_cb", ctx,
+         "ctx->passphrase_cb=%p/%p",
+         ctx->passphrase_cb, ctx->passphrase_cb_value);
+  if (r_cb)
+    *r_cb = ctx->passphrase_cb;
+  if (r_cb_value)
+    *r_cb_value = ctx->passphrase_cb_value;
 }
 
 
-/**
- * gpgme_set_textmode:
- * @ctx: the context
- * @yes: boolean flag whether textmode should be enabled
- * 
- * Enable or disable the use of the special textmode.  Textmode is for example
- * used for the RFC2015 signatures; note that the updated RFC 3156 mandates 
- * that the MUA does some preparations so that textmode is not needed anymore.
- **/
+/* This function sets a callback function to be used as a progress
+   indicator.  */
 void
-gpgme_set_textmode (GpgmeCtx ctx, int yes)
+gpgme_set_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t cb, void *cb_value)
 {
+  TRACE2 (DEBUG_CTX, "gpgme_set_progress_cb", ctx, "progress_cb=%p/%p",
+         cb, cb_value);
+  ctx->progress_cb = cb;
+  ctx->progress_cb_value = cb_value;
+}
+
+
+/* This function returns the callback function to be used as a
+   progress indicator.  */
+void
+gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *r_cb,
+                      void **r_cb_value)
+{
+  TRACE2 (DEBUG_CTX, "gpgme_get_progress_cb", ctx, "ctx->progress_cb=%p/%p",
+         ctx->progress_cb, ctx->progress_cb_value);
+  if (r_cb)
+    *r_cb = ctx->progress_cb;
+  if (r_cb_value)
+    *r_cb_value = ctx->progress_cb_value;
+}
+
+
+/* Set the I/O callback functions for CTX to IO_CBS.  */
+void
+gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
+{
+  if (io_cbs)
+    {
+      TRACE6 (DEBUG_CTX, "gpgme_set_io_cbs", ctx,
+             "io_cbs=%p (add=%p/%p, remove=%p, event=%p/%p",
+             io_cbs, io_cbs->add, io_cbs->add_priv, io_cbs->remove,
+             io_cbs->event, io_cbs->event_priv);
+      ctx->io_cbs = *io_cbs;
+    }
+  else
+    {
+      TRACE1 (DEBUG_CTX, "gpgme_set_io_cbs", ctx,
+             "io_cbs=%p (default)", io_cbs);
+      ctx->io_cbs.add = NULL;
+      ctx->io_cbs.add_priv = NULL;
+      ctx->io_cbs.remove = NULL;
+      ctx->io_cbs.event = NULL;
+      ctx->io_cbs.event_priv = NULL;
+    }
+}
+
+
+/* This function returns the callback function for I/O.  */
+void
+gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
+{
+  TRACE6 (DEBUG_CTX, "gpgme_get_io_cbs", ctx,
+         "io_cbs=%p, ctx->io_cbs.add=%p/%p, .remove=%p, .event=%p/%p",
+         io_cbs, io_cbs->add, io_cbs->add_priv, io_cbs->remove,
+         io_cbs->event, io_cbs->event_priv);
+
+  *io_cbs = ctx->io_cbs;
+}
+
+\f
+/* This function sets the locale for the context CTX, or the default
+   locale if CTX is a null pointer.  */
+gpgme_error_t
+gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
+{
+  int failed = 0;
+  char *new_lc_ctype = NULL;
+  char *new_lc_messages = NULL;
+
+  TRACE_BEG2 (DEBUG_CTX, "gpgme_set_locale", ctx,
+              "category=%i, value=%s", category, value ? value : "(null)");
+
+#define PREPARE_ONE_LOCALE(lcat, ucat)                         \
+  if (!failed && value                                         \
+      && (category == LC_ALL || category == LC_ ## ucat))      \
+    {                                                          \
+      new_lc_ ## lcat = strdup (value);                                \
+      if (!new_lc_ ## lcat)                                    \
+        failed = 1;                                            \
+    }
+
+  PREPARE_ONE_LOCALE (ctype, CTYPE);
+#ifdef LC_MESSAGES
+  PREPARE_ONE_LOCALE (messages, MESSAGES);
+#endif
+
+  if (failed)
+    {
+      int saved_errno = errno;
+
+      if (new_lc_ctype)
+       free (new_lc_ctype);
+      if (new_lc_messages)
+       free (new_lc_messages);
+
+      return TRACE_ERR (gpg_error_from_errno (saved_errno));
+    }
+
+#define SET_ONE_LOCALE(lcat, ucat)                     \
+  if (category == LC_ALL || category == LC_ ## ucat)   \
+    {                                                  \
+      if (ctx)                                         \
+       {                                               \
+         if (ctx->lc_ ## lcat)                         \
+           free (ctx->lc_ ## lcat);                    \
+         ctx->lc_ ## lcat = new_lc_ ## lcat;           \
+       }                                               \
+      else                                             \
+       {                                               \
+         if (def_lc_ ## lcat)                          \
+           free (def_lc_ ## lcat);                     \
+         def_lc_ ## lcat = new_lc_ ## lcat;            \
+       }                                               \
+    }
+
   if (!ctx)
-    return;
-  ctx->use_textmode = yes;
+    LOCK (def_lc_lock);
+  SET_ONE_LOCALE (ctype, CTYPE);
+#ifdef LC_MESSAGES
+  SET_ONE_LOCALE (messages, MESSAGES);
+#endif
+  if (!ctx)
+    UNLOCK (def_lc_lock);
+
+  return TRACE_ERR (0);
 }
 
-/**
- * gpgme_get_textmode:
- * @ctx: the context
- * 
- * Return the state of the textmode flag which can be changed using
- * gpgme_set_textmode().
- * 
- * Return value: Boolean whether textmode is to be used.
- **/
-int 
-gpgme_get_textmode (GpgmeCtx ctx)
+\f
+/* Get the information about the configured engines.  A pointer to the
+   first engine in the statically allocated linked list is returned.
+   The returned data is valid until the next gpgme_ctx_set_engine_info.  */
+gpgme_engine_info_t
+gpgme_ctx_get_engine_info (gpgme_ctx_t ctx)
 {
-  return ctx && ctx->use_textmode;
+  TRACE1 (DEBUG_CTX, "gpgme_ctx_get_engine_info", ctx,
+         "ctx->engine_info=%p", ctx->engine_info);
+  return ctx->engine_info;
 }
 
 
-/**
- * gpgme_set_keylist_mode:
- * @ctx: the context
- * @mode: listing mode
- * 
- * This function changes the default behaviour of the keylisting functions.
- * Defines values for @mode are: %0 = normal, %1 = fast listing without
- * information about key validity.
- **/
+/* Set the engine info for the context CTX, protocol PROTO, to the
+   file name FILE_NAME and the home directory HOME_DIR.  */
+gpgme_error_t
+gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,
+                          const char *file_name, const char *home_dir)
+{
+  gpgme_error_t err;
+  TRACE_BEG4 (DEBUG_CTX, "gpgme_ctx_set_engine_info", ctx,
+             "protocol=%i (%s), file_name=%s, home_dir=%s",
+             proto, gpgme_get_protocol_name (proto)
+             ? gpgme_get_protocol_name (proto) : "unknown",
+             file_name ? file_name : "(default)",
+             home_dir ? home_dir : "(default)");
+             
+  /* Shut down the engine when changing engine info.  */
+  if (ctx->engine)
+    {
+      TRACE_LOG1 ("releasing ctx->engine=%p", ctx->engine);
+      _gpgme_engine_release (ctx->engine);
+      ctx->engine = NULL;
+    }
+  err = _gpgme_set_engine_info (ctx->engine_info, proto,
+                               file_name, home_dir);
+  return TRACE_ERR (err);
+}
+
+\f
+/* Clear all notation data from the context.  */
 void
-gpgme_set_keylist_mode (GpgmeCtx ctx, int mode)
+gpgme_sig_notation_clear (gpgme_ctx_t ctx)
 {
+  gpgme_sig_notation_t notation;
+  TRACE (DEBUG_CTX, "gpgme_sig_notation_clear", ctx);
+
   if (!ctx)
     return;
-  ctx->keylist_mode = mode;
+
+  notation = ctx->sig_notations;
+  while (notation)
+    {
+      gpgme_sig_notation_t next_notation = notation->next;
+      _gpgme_sig_notation_free (notation);
+      notation = next_notation;
+    }
 }
 
 
-/**
- * gpgme_set_passphrase_cb:
- * @ctx: the context 
- * @cb: A callback function
- * @cb_value: The value passed to the callback function
- * 
- * This function sets a callback function to be used to pass a passphrase
- * to gpg. The preferred way to handle this is by using the gpg-agent, but
- * because that beast is not ready for real use, you can use this passphrase
- * thing.
- *
- * The callback function is defined as:
- * <literal>
- * typedef const char *(*GpgmePassphraseCb)(void*cb_value,
- *                                          const char *desc,
- *                                          void **r_hd);
- * </literal>
- * and called whenever gpgme needs a passphrase. DESC will have a nice
- * text, to be used to prompt for the passphrase and R_HD is just a parameter
- * to be used by the callback it self.  Because the callback returns a const
- * string, the callback might want to know when it can release resources
- * assocated with that returned string; gpgme helps here by calling this
- * passphrase callback with an DESC of %NULL as soon as it does not need
- * the returned string anymore.  The callback function might then choose
- * to release resources depending on R_HD.
- *
- **/
-void
-gpgme_set_passphrase_cb (GpgmeCtx ctx, GpgmePassphraseCb cb, void *cb_value)
+/* 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
+   VALUE should be a policy URL.  The flag
+   GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
+   data, and false for policy URLs.  */
+gpgme_error_t
+gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
+                       const char *value, gpgme_sig_notation_flags_t flags)
+{
+  gpgme_error_t err;
+  gpgme_sig_notation_t notation;
+  gpgme_sig_notation_t *lastp;
+
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_sig_notation_add", ctx,
+             "name=%s, value=%s, flags=0x%x",
+             name ? name : "(null)", value ? value : "(null)",
+             flags);
+  
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  if (name)
+    flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
+  else
+    flags &= ~GPGME_SIG_NOTATION_HUMAN_READABLE;
+
+  err = _gpgme_sig_notation_create (&notation, name, name ? strlen (name) : 0,
+                                   value, value ? strlen (value) : 0, flags);
+  if (err)
+    return TRACE_ERR (err);
+
+  lastp = &ctx->sig_notations;
+  while (*lastp)
+    lastp = &(*lastp)->next;
+
+  *lastp = notation;
+  return TRACE_ERR (0);
+}
+
+
+/* Get the sig notations for this context.  */
+gpgme_sig_notation_t
+gpgme_sig_notation_get (gpgme_ctx_t ctx)
 {
-  if (ctx)
+  if (!ctx)
     {
-      ctx->passphrase_cb = cb;
-      ctx->passphrase_cb_value = cb_value;
+      TRACE (DEBUG_CTX, "gpgme_sig_notation_get", ctx);
+      return NULL;
     }
+  TRACE1 (DEBUG_CTX, "gpgme_sig_notation_get", ctx,
+         "ctx->sig_notations=%p", ctx->sig_notations);
+
+  return ctx->sig_notations;
 }
+  
+\f
+const char *
+gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
+{
+  switch (algo)
+    {
+    case GPGME_PK_RSA:
+      return "RSA";
 
-/**
- * gpgme_set_progress_cb:
- * @ctx: the context 
- * @cb: A callback function
- * @cb_value: The value passed to the callback function
- * 
- * This function sets a callback function to be used as a progress indicator.
- *
- * The callback function is defined as:
- * <literal>
- * typedef void (*GpgmeProgressCb) (void *cb_value,
- *                                  const char *what, int type,
- *                                  int curretn, int total);
- * </literal>
- * For details on the progress events, see the entry for the PROGRESS
- * status in the file doc/DETAILS of the GnuPG distribution.
- **/
-void
-gpgme_set_progress_cb (GpgmeCtx ctx, GpgmeProgressCb cb, void *cb_value)
+    case GPGME_PK_RSA_E:
+      return "RSA-E";
+
+    case GPGME_PK_RSA_S:
+      return "RSA-S";
+
+    case GPGME_PK_ELG_E:
+      return "ELG-E";
+
+    case GPGME_PK_DSA:
+      return "DSA";
+
+    case GPGME_PK_ELG:
+      return "ELG";
+
+    default:
+      return NULL;
+    }
+}
+
+
+const char *
+gpgme_hash_algo_name (gpgme_hash_algo_t algo)
 {
-  if (ctx)
+  switch (algo)
     {
-      ctx->progress_cb = cb;
-      ctx->progress_cb_value = cb_value;
+    case GPGME_MD_MD5:
+      return "MD5";
+
+    case GPGME_MD_SHA1:
+      return "SHA1";
+
+    case GPGME_MD_RMD160:
+      return "RIPEMD160";
+
+    case GPGME_MD_MD2:
+      return "MD2";
+
+    case GPGME_MD_TIGER:
+      return "TIGER192";
+
+    case GPGME_MD_HAVAL:
+      return "HAVAL";
+
+    case GPGME_MD_SHA256:
+      return "SHA256";
+
+    case GPGME_MD_SHA384:
+      return "SHA384";
+
+    case GPGME_MD_SHA512:
+      return "SHA512";
+
+    case GPGME_MD_MD4:
+      return "MD4";
+
+    case GPGME_MD_CRC32:
+      return "CRC32";
+
+    case GPGME_MD_CRC32_RFC1510:
+      return "CRC32RFC1510";
+
+    case GPGME_MD_CRC24_RFC2440:
+      return "CRC24RFC2440";
+
+    default:
+      return NULL;
     }
 }