2007-07-17 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / rungpg.c
index 3907c3f..a8fc8ad 100644 (file)
@@ -1,6 +1,6 @@
 /* rungpg.c - Gpg Engine.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 g10 Code GmbH
  
    This file is part of GPGME.
  
@@ -28,6 +28,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <unistd.h>
+#include <locale.h>
 
 #include "gpgme.h"
 #include "util.h"
@@ -72,6 +73,9 @@ struct engine_gpg
 {
   char *file_name;
 
+  char *lc_messages;
+  char *lc_ctype;
+
   struct arg_and_data_s *arglist;
   struct arg_and_data_s **argtail;
 
@@ -181,8 +185,10 @@ close_notify_handler (int fd, void *opaque)
     }
 }
 
+/* If FRONT is true, push at the front of the list.  Use this for
+   options added late in the process.  */
 static gpgme_error_t
-add_arg (engine_gpg_t gpg, const char *arg)
+add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
 {
   struct arg_and_data_s *a;
 
@@ -192,16 +198,38 @@ add_arg (engine_gpg_t gpg, const char *arg)
   a = malloc (sizeof *a + strlen (arg));
   if (!a)
     return gpg_error_from_errno (errno);
-  a->next = NULL;
+
   a->data = NULL;
   a->dup_to = -1;
   strcpy (a->arg, arg);
-  *gpg->argtail = a;
-  gpg->argtail = &a->next;
+  if (front)
+    {
+      a->next = gpg->arglist;
+      if (!gpg->arglist)
+       {
+         /* If this is the first argument, we need to update the tail
+            pointer.  */
+         gpg->argtail = &a->next;
+       }
+      gpg->arglist = a;
+    }
+  else
+    {
+      a->next = NULL;
+      *gpg->argtail = a;
+      gpg->argtail = &a->next;
+    }
+
   return 0;
 }
 
 static gpgme_error_t
+add_arg (engine_gpg_t gpg, const char *arg)
+{
+  return add_arg_ext (gpg, arg, 0);
+}
+
+static gpgme_error_t
 add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
 {
   struct arg_and_data_s *a;
@@ -317,6 +345,11 @@ gpg_release (void *engine)
   if (gpg->file_name)
     free (gpg->file_name);
 
+  if (gpg->lc_messages)
+    free (gpg->lc_messages);
+  if (gpg->lc_ctype)
+    free (gpg->lc_ctype);
+
   while (gpg->arglist)
     {
       struct arg_and_data_s *next = gpg->arglist->next;
@@ -340,8 +373,7 @@ gpg_release (void *engine)
 
 
 static gpgme_error_t
-gpg_new (void **engine, const char *file_name, const char *home_dir,
-        const char *lc_ctype, const char *lc_messages)
+gpg_new (void **engine, const char *file_name, const char *home_dir)
 {
   engine_gpg_t gpg;
   gpgme_error_t rc = 0;
@@ -444,7 +476,10 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
 
   if (isatty (1))
     {
-      if (ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)))
+      int err;
+
+      err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+      if (err)
        rc = gpg_error_from_errno (errno);
       else
        {
@@ -468,24 +503,6 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
        goto leave;
     }
 
-  if (lc_ctype)
-    {
-      rc = add_arg (gpg, "--lc-ctype");
-      if (!rc)
-       rc = add_arg (gpg, lc_ctype);
-      if (rc)
-       goto leave;
-    }
-
-  if (lc_messages)
-    {
-      rc = add_arg (gpg, "--lc-messages");
-      if (!rc)
-       rc = add_arg (gpg, lc_messages);
-      if (rc)
-       goto leave;
-    }
-
  leave:
   if (rc)
     gpg_release (gpg);
@@ -495,6 +512,48 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
 }
 
 
+static gpgme_error_t
+gpg_set_locale (void *engine, int category, const char *value)
+{
+  engine_gpg_t gpg = engine;
+
+  if (category == LC_CTYPE)
+    {
+      if (gpg->lc_ctype)
+        {
+          free (gpg->lc_ctype);
+          gpg->lc_ctype = NULL;
+        }
+      if (value)
+       {
+         gpg->lc_ctype = strdup (value);
+         if (!gpg->lc_ctype)
+           return gpg_error_from_syserror ();
+       }
+    }
+#ifdef LC_MESSAGES
+  else if (category == LC_MESSAGES)
+    {
+      if (gpg->lc_messages)
+        {
+          free (gpg->lc_messages);
+          gpg->lc_messages = NULL;
+        }
+      if (value)
+       {
+         gpg->lc_messages = strdup (value);
+         if (!gpg->lc_messages)
+           return gpg_error_from_syserror ();
+       }
+    }
+#endif /* LC_MESSAGES */
+  else
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  return 0;
+}
+
+
 /* Note, that the status_handler is allowed to modifiy the args
    value.  */
 static void
@@ -943,7 +1002,8 @@ read_status (engine_gpg_t gpg)
                             received and the next thing will be that
                             the command handler does its action.  */
                          if (nread > 1)
-                           DEBUG0 ("ERROR, unexpected data in read_status");
+                           TRACE0 (DEBUG_CTX, "gpgme:read_status", 0,
+                                   "error: unexpected data");
 
                          add_io_cb (gpg, gpg->cmd.fd, 0,
                                     command_handler, gpg,
@@ -1163,6 +1223,24 @@ start (engine_gpg_t gpg)
   if (!gpg->file_name && !_gpgme_get_gpg_path ())
     return gpg_error (GPG_ERR_INV_ENGINE);
 
+  if (gpg->lc_ctype)
+    {
+      rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
+      if (!rc)
+       rc = add_arg_ext (gpg, "--lc-ctype", 1);
+      if (rc)
+       return rc;
+    }
+
+  if (gpg->lc_messages)
+    {
+      rc = add_arg_ext (gpg, gpg->lc_messages, 1);
+      if (!rc)
+       rc = add_arg_ext (gpg, "--lc-messages", 1);
+      if (rc)
+       return rc;
+    }
+
   rc = build_argv (gpg);
   if (rc)
     return rc;
@@ -2012,9 +2090,11 @@ struct engine_ops _gpgme_engine_ops_gpg =
 
     /* Member functions.  */
     gpg_release,
+    NULL,                              /* reset */
     gpg_set_status_handler,
     gpg_set_command_handler,
     gpg_set_colon_line_handler,
+    gpg_set_locale,
     gpg_decrypt,
     gpg_delete,
     gpg_edit,