LCOV - code coverage report
Current view: top level - src - engine-gpg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1201 1654 72.6 %
Date: 2018-11-15 08:49:49 Functions: 65 69 94.2 %

          Line data    Source code
       1             : /* engine-gpg.c - Gpg Engine.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
       4             :                  2009, 2010, 2012, 2013 g10 Code GmbH
       5             : 
       6             :    This file is part of GPGME.
       7             : 
       8             :    GPGME is free software; you can redistribute it and/or modify it
       9             :    under the terms of the GNU Lesser General Public License as
      10             :    published by the Free Software Foundation; either version 2.1 of
      11             :    the License, or (at your option) any later version.
      12             : 
      13             :    GPGME is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    Lesser General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU Lesser General Public
      19             :    License along with this program; if not, see <https://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #if HAVE_CONFIG_H
      23             : #include <config.h>
      24             : #endif
      25             : #include <stdio.h>
      26             : #include <stdlib.h>
      27             : #include <string.h>
      28             : #include <assert.h>
      29             : #ifdef HAVE_UNISTD_H
      30             : # include <unistd.h>
      31             : #endif
      32             : #ifdef HAVE_LOCALE_H
      33             : #include <locale.h>
      34             : #endif
      35             : 
      36             : #include "gpgme.h"
      37             : #include "util.h"
      38             : #include "ops.h"
      39             : #include "wait.h"
      40             : #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
      41             : #include "priv-io.h"
      42             : #include "sema.h"
      43             : #include "debug.h"
      44             : #include "data.h"
      45             : #include "mbox-util.h"
      46             : 
      47             : #include "engine-backend.h"
      48             : 
      49             : 
      50             : /* This type is used to build a list of gpg arguments and data
      51             :    sources/sinks.  */
      52             : struct arg_and_data_s
      53             : {
      54             :   struct arg_and_data_s *next;
      55             :   gpgme_data_t data;  /* If this is not NULL, use arg below.  */
      56             :   int inbound;     /* True if this is used for reading from gpg.  */
      57             :   int dup_to;
      58             :   int print_fd;    /* Print the fd number and not the special form of it.  */
      59             :   int *arg_locp;   /* Write back the argv idx of this argument when
      60             :                       building command line to this location.  */
      61             :   char arg[1];     /* Used if data above is not used.  */
      62             : };
      63             : 
      64             : 
      65             : struct fd_data_map_s
      66             : {
      67             :   gpgme_data_t data;
      68             :   int inbound;  /* true if this is used for reading from gpg */
      69             :   int dup_to;
      70             :   int fd;       /* the fd to use */
      71             :   int peer_fd;  /* the other side of the pipe */
      72             :   int arg_loc;  /* The index into the argv for translation purposes.  */
      73             :   void *tag;
      74             : };
      75             : 
      76             : 
      77             : /* NB.: R_LINE is allocated an gpgrt function and thus gpgrt_free
      78             :  * shall be used to release it.  This takes care of custom memory
      79             :  * allocators and avoids problems on Windows with different runtimes
      80             :  * used for libgpg-error/gpgrt and gpgme.  */
      81             : typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
      82             : 
      83             : struct engine_gpg
      84             : {
      85             :   char *file_name;
      86             :   char *version;
      87             : 
      88             :   char *lc_messages;
      89             :   char *lc_ctype;
      90             : 
      91             :   struct arg_and_data_s *arglist;
      92             :   struct arg_and_data_s **argtail;
      93             : 
      94             :   struct
      95             :   {
      96             :     int fd[2];
      97             :     int arg_loc;
      98             :     size_t bufsize;
      99             :     char *buffer;
     100             :     size_t readpos;
     101             :     int eof;
     102             :     engine_status_handler_t fnc;
     103             :     void *fnc_value;
     104             :     gpgme_status_cb_t mon_cb;
     105             :     void *mon_cb_value;
     106             :     void *tag;
     107             :   } status;
     108             : 
     109             :   /* This is a kludge - see the comment at colon_line_handler.  */
     110             :   struct
     111             :   {
     112             :     int fd[2];
     113             :     int arg_loc;
     114             :     size_t bufsize;
     115             :     char *buffer;
     116             :     size_t readpos;
     117             :     int eof;
     118             :     engine_colon_line_handler_t fnc;  /* this indicate use of this structrue */
     119             :     void *fnc_value;
     120             :     void *tag;
     121             :     colon_preprocessor_t preprocess_fnc;
     122             :   } colon;
     123             : 
     124             :   char **argv;
     125             :   struct fd_data_map_s *fd_data_map;
     126             : 
     127             :   /* stuff needed for interactive (command) mode */
     128             :   struct
     129             :   {
     130             :     int used;
     131             :     int fd;
     132             :     void *cb_data;
     133             :     int idx;            /* Index in fd_data_map */
     134             :     gpgme_status_code_t code;  /* last code */
     135             :     char *keyword;       /* what has been requested (malloced) */
     136             :     engine_command_handler_t fnc;
     137             :     void *fnc_value;
     138             :   } cmd;
     139             : 
     140             :   struct gpgme_io_cbs io_cbs;
     141             :   gpgme_pinentry_mode_t pinentry_mode;
     142             :   char request_origin[10];
     143             :   char *auto_key_locate;
     144             :   char *trust_model;
     145             : 
     146             :   struct {
     147             :     unsigned int no_symkey_cache : 1;
     148             :     unsigned int offline : 1;
     149             :     unsigned int ignore_mdc_error : 1;
     150             :   } flags;
     151             : 
     152             :   /* NULL or the data object fed to --override_session_key-fd.  */
     153             :   gpgme_data_t override_session_key;
     154             : 
     155             :   /* Memory data containing diagnostics (--logger-fd) of gpg */
     156             :   gpgme_data_t diagnostics;
     157             : };
     158             : 
     159             : typedef struct engine_gpg *engine_gpg_t;
     160             : 
     161             : 
     162             : static void
     163        2805 : gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
     164             : {
     165        2805 :   engine_gpg_t gpg = engine;
     166             : 
     167        2805 :   TRACE3 (DEBUG_ENGINE, "gpgme:gpg_io_event", gpg,
     168             :           "event %p, type %d, type_data %p",
     169             :           gpg->io_cbs.event, type, type_data);
     170        2805 :   if (gpg->io_cbs.event)
     171        2805 :     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
     172        2804 : }
     173             : 
     174             : 
     175             : static void
     176        4895 : close_notify_handler (int fd, void *opaque)
     177             : {
     178        4895 :   engine_gpg_t gpg = opaque;
     179        4895 :   assert (fd != -1);
     180             : 
     181        4895 :   if (gpg->status.fd[0] == fd)
     182             :     {
     183         748 :       if (gpg->status.tag)
     184         748 :         (*gpg->io_cbs.remove) (gpg->status.tag);
     185         748 :       gpg->status.fd[0] = -1;
     186             :     }
     187        4147 :   else if (gpg->status.fd[1] == fd)
     188         740 :     gpg->status.fd[1] = -1;
     189        3407 :   else if (gpg->colon.fd[0] == fd)
     190             :     {
     191         338 :       if (gpg->colon.tag)
     192         338 :         (*gpg->io_cbs.remove) (gpg->colon.tag);
     193         338 :       gpg->colon.fd[0] = -1;
     194             :     }
     195        3069 :   else if (gpg->colon.fd[1] == fd)
     196         333 :     gpg->colon.fd[1] = -1;
     197        2736 :   else if (gpg->cmd.fd == fd)
     198          99 :     gpg->cmd.fd = -1;
     199        2637 :   else if (gpg->fd_data_map)
     200             :     {
     201             :       int i;
     202             : 
     203        4608 :       for (i = 0; gpg->fd_data_map[i].data; i++)
     204             :         {
     205        4608 :           if (gpg->fd_data_map[i].fd == fd)
     206             :             {
     207        1273 :               if (gpg->fd_data_map[i].tag)
     208        1273 :                 (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
     209        1273 :               gpg->fd_data_map[i].fd = -1;
     210        1273 :               break;
     211             :             }
     212        3335 :           if (gpg->fd_data_map[i].peer_fd == fd)
     213             :             {
     214        1364 :               gpg->fd_data_map[i].peer_fd = -1;
     215        1364 :               break;
     216             :             }
     217             :         }
     218             :     }
     219        4895 : }
     220             : 
     221             : /* If FRONT is true, push at the front of the list.  Use this for
     222             :    options added late in the process.  */
     223             : static gpgme_error_t
     224       15552 : _add_arg (engine_gpg_t gpg, const char *prefix, const char *arg, size_t arglen,
     225             :           int front, int *arg_locp)
     226             : {
     227             :   struct arg_and_data_s *a;
     228       15552 :   size_t prefixlen = prefix? strlen (prefix) : 0;
     229             : 
     230       15552 :   assert (gpg);
     231       15552 :   assert (arg);
     232             : 
     233       15552 :   a = malloc (sizeof *a + prefixlen + arglen);
     234       15552 :   if (!a)
     235           0 :     return gpg_error_from_syserror ();
     236             : 
     237       15552 :   a->data = NULL;
     238       15552 :   a->dup_to = -1;
     239       15552 :   a->arg_locp = arg_locp;
     240             : 
     241       15552 :   if (prefixlen)
     242          10 :     memcpy (a->arg, prefix, prefixlen);
     243       15552 :   memcpy (a->arg + prefixlen, arg, arglen);
     244       15552 :   a->arg[prefixlen + arglen] = 0;
     245       15552 :   if (front)
     246             :     {
     247         709 :       a->next = gpg->arglist;
     248         709 :       if (!gpg->arglist)
     249             :         {
     250             :           /* If this is the first argument, we need to update the tail
     251             :              pointer.  */
     252           0 :           gpg->argtail = &a->next;
     253             :         }
     254         709 :       gpg->arglist = a;
     255             :     }
     256             :   else
     257             :     {
     258       14843 :       a->next = NULL;
     259       14843 :       *gpg->argtail = a;
     260       14843 :       gpg->argtail = &a->next;
     261             :     }
     262             : 
     263       15552 :   return 0;
     264             : }
     265             : 
     266             : 
     267             : static gpgme_error_t
     268         707 : add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
     269             : {
     270         707 :   return _add_arg (gpg, NULL, arg, strlen (arg), front, NULL);
     271             : }
     272             : 
     273             : static gpgme_error_t
     274         753 : add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
     275             : {
     276         753 :   return _add_arg (gpg, NULL, arg, strlen (arg), 0, locp);
     277             : }
     278             : 
     279             : static gpgme_error_t
     280       14052 : add_arg (engine_gpg_t gpg, const char *arg)
     281             : {
     282       14052 :   return _add_arg (gpg, NULL, arg, strlen (arg), 0, NULL);
     283             : }
     284             : 
     285             : static gpgme_error_t
     286           6 : add_arg_pfx (engine_gpg_t gpg, const char *prefix, const char *arg)
     287             : {
     288           6 :   return _add_arg (gpg, prefix, arg, strlen (arg), 0, NULL);
     289             : }
     290             : 
     291             : static gpgme_error_t
     292           8 : add_arg_len (engine_gpg_t gpg, const char *prefix,
     293             :              const char *arg, size_t arglen)
     294             : {
     295           8 :   return _add_arg (gpg, prefix, arg, arglen, 0, NULL);
     296             : }
     297             : 
     298             : 
     299             : static gpgme_error_t
     300        1386 : add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
     301             : {
     302             :   struct arg_and_data_s *a;
     303             : 
     304        1386 :   assert (gpg);
     305        1386 :   assert (data);
     306             : 
     307        1386 :   a = malloc (sizeof *a - 1);
     308        1386 :   if (!a)
     309           0 :     return gpg_error_from_syserror ();
     310        1386 :   a->next = NULL;
     311        1386 :   a->data = data;
     312        1386 :   a->inbound = inbound;
     313        1386 :   a->arg_locp = NULL;
     314             : 
     315        1386 :   if (dup_to == -2)
     316             :     {
     317         853 :       a->print_fd = 1;
     318         853 :       a->dup_to = -1;
     319             :     }
     320             :   else
     321             :     {
     322         533 :       a->print_fd = 0;
     323         533 :       a->dup_to = dup_to;
     324             :     }
     325        1386 :   *gpg->argtail = a;
     326        1386 :   gpg->argtail = &a->next;
     327        1386 :   return 0;
     328             : }
     329             : 
     330             : 
     331             : /* Return true if the engine's version is at least VERSION.  */
     332             : static int
     333        1341 : have_gpg_version (engine_gpg_t gpg, const char *version)
     334             : {
     335        1341 :   return _gpgme_compare_versions (gpg->version, version);
     336             : }
     337             : 
     338             : 
     339             : 
     340             : static char *
     341         527 : gpg_get_version (const char *file_name)
     342             : {
     343         527 :   return _gpgme_get_program_version (file_name ? file_name
     344             :                                      : _gpgme_get_default_gpg_name ());
     345             : }
     346             : 
     347             : 
     348             : static const char *
     349         117 : gpg_get_req_version (void)
     350             : {
     351         117 :   return "1.4.0";
     352             : }
     353             : 
     354             : 
     355             : static void
     356         721 : free_argv (char **argv)
     357             : {
     358             :   int i;
     359             : 
     360       19082 :   for (i = 0; argv[i]; i++)
     361       18361 :     free (argv[i]);
     362         721 :   free (argv);
     363         721 : }
     364             : 
     365             : 
     366             : static void
     367         726 : free_fd_data_map (struct fd_data_map_s *fd_data_map)
     368             : {
     369             :   int i;
     370             : 
     371         726 :   if (!fd_data_map)
     372           0 :     return;
     373             : 
     374        2058 :   for (i = 0; fd_data_map[i].data; i++)
     375             :     {
     376        1332 :       if (fd_data_map[i].fd != -1)
     377          55 :         _gpgme_io_close (fd_data_map[i].fd);
     378        1332 :       if (fd_data_map[i].peer_fd != -1)
     379           0 :         _gpgme_io_close (fd_data_map[i].peer_fd);
     380             :       /* Don't release data because this is only a reference.  */
     381             :     }
     382         726 :   free (fd_data_map);
     383             : }
     384             : 
     385             : 
     386             : static gpgme_error_t
     387         750 : gpg_cancel (void *engine)
     388             : {
     389         750 :   engine_gpg_t gpg = engine;
     390             : 
     391         750 :   if (!gpg)
     392           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     393             : 
     394             :   /* If gpg may be waiting for a cmd, close the cmd fd first.  On
     395             :      Windows, close operations block on the reader/writer thread.  */
     396         750 :   if (gpg->cmd.used)
     397             :     {
     398         103 :       if (gpg->cmd.fd != -1)
     399          99 :         _gpgme_io_close (gpg->cmd.fd);
     400           4 :       else if (gpg->fd_data_map
     401           0 :                && gpg->fd_data_map[gpg->cmd.idx].fd != -1)
     402           0 :         _gpgme_io_close (gpg->fd_data_map[gpg->cmd.idx].fd);
     403             :     }
     404             : 
     405         751 :   if (gpg->status.fd[0] != -1)
     406          32 :     _gpgme_io_close (gpg->status.fd[0]);
     407         751 :   if (gpg->status.fd[1] != -1)
     408           0 :     _gpgme_io_close (gpg->status.fd[1]);
     409         751 :   if (gpg->colon.fd[0] != -1)
     410           6 :     _gpgme_io_close (gpg->colon.fd[0]);
     411         751 :   if (gpg->colon.fd[1] != -1)
     412           0 :     _gpgme_io_close (gpg->colon.fd[1]);
     413         751 :   if (gpg->fd_data_map)
     414             :     {
     415         727 :       free_fd_data_map (gpg->fd_data_map);
     416         726 :       gpg->fd_data_map = NULL;
     417             :     }
     418             : 
     419         750 :   return 0;
     420             : }
     421             : 
     422             : static void
     423         721 : gpg_release (void *engine)
     424             : {
     425         721 :   engine_gpg_t gpg = engine;
     426             : 
     427         721 :   if (!gpg)
     428           0 :     return;
     429             : 
     430         721 :   gpg_cancel (engine);
     431             : 
     432         721 :   if (gpg->file_name)
     433         720 :     free (gpg->file_name);
     434         721 :   if (gpg->version)
     435         721 :     free (gpg->version);
     436             : 
     437         721 :   if (gpg->lc_messages)
     438         153 :     free (gpg->lc_messages);
     439         721 :   if (gpg->lc_ctype)
     440         153 :     free (gpg->lc_ctype);
     441             : 
     442       17658 :   while (gpg->arglist)
     443             :     {
     444       16216 :       struct arg_and_data_s *next = gpg->arglist->next;
     445             : 
     446       16216 :       free (gpg->arglist);
     447       16216 :       gpg->arglist = next;
     448             :     }
     449             : 
     450         721 :   if (gpg->status.buffer)
     451         721 :     free (gpg->status.buffer);
     452         721 :   if (gpg->colon.buffer)
     453         333 :     free (gpg->colon.buffer);
     454         721 :   if (gpg->argv)
     455         721 :     free_argv (gpg->argv);
     456         721 :   if (gpg->cmd.keyword)
     457          41 :     free (gpg->cmd.keyword);
     458         721 :   free (gpg->auto_key_locate);
     459         721 :   free (gpg->trust_model);
     460             : 
     461         721 :   gpgme_data_release (gpg->override_session_key);
     462         721 :   gpgme_data_release (gpg->diagnostics);
     463             : 
     464         721 :   free (gpg);
     465             : }
     466             : 
     467             : 
     468             : static gpgme_error_t
     469         754 : gpg_new (void **engine, const char *file_name, const char *home_dir,
     470             :          const char *version)
     471             : {
     472             :   engine_gpg_t gpg;
     473         754 :   gpgme_error_t rc = 0;
     474         754 :   char *dft_display = NULL;
     475             :   char dft_ttyname[64];
     476         754 :   char *dft_ttytype = NULL;
     477         754 :   char *env_tty = NULL;
     478             : 
     479         754 :   gpg = calloc (1, sizeof *gpg);
     480         754 :   if (!gpg)
     481           0 :     return gpg_error_from_syserror ();
     482             : 
     483         754 :   if (file_name)
     484             :     {
     485         753 :       gpg->file_name = strdup (file_name);
     486         753 :       if (!gpg->file_name)
     487             :         {
     488           0 :           rc = gpg_error_from_syserror ();
     489           0 :           goto leave;
     490             :         }
     491             :     }
     492             : 
     493         754 :   if (version)
     494             :     {
     495         754 :       gpg->version = strdup (version);
     496         754 :       if (!gpg->version)
     497             :         {
     498           0 :           rc = gpg_error_from_syserror ();
     499           0 :           goto leave;
     500             :         }
     501             :     }
     502             : 
     503         754 :   gpg->argtail = &gpg->arglist;
     504         754 :   gpg->status.fd[0] = -1;
     505         754 :   gpg->status.fd[1] = -1;
     506         754 :   gpg->colon.fd[0] = -1;
     507         754 :   gpg->colon.fd[1] = -1;
     508         754 :   gpg->cmd.fd = -1;
     509         754 :   gpg->cmd.idx = -1;
     510             : 
     511             :   /* Allocate the read buffer for the status pipe.  */
     512         754 :   gpg->status.bufsize = 1024;
     513         754 :   gpg->status.readpos = 0;
     514         754 :   gpg->status.buffer = malloc (gpg->status.bufsize);
     515         754 :   if (!gpg->status.buffer)
     516             :     {
     517           0 :       rc = gpg_error_from_syserror ();
     518           0 :       goto leave;
     519             :     }
     520             :   /* In any case we need a status pipe - create it right here and
     521             :      don't handle it with our generic gpgme_data_t mechanism.  */
     522         754 :   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
     523             :     {
     524           0 :       rc = gpg_error_from_syserror ();
     525           0 :       goto leave;
     526             :     }
     527         754 :   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
     528             :                                   close_notify_handler, gpg)
     529         754 :       || _gpgme_io_set_close_notify (gpg->status.fd[1],
     530             :                                      close_notify_handler, gpg))
     531             :     {
     532           0 :       rc = gpg_error (GPG_ERR_GENERAL);
     533           0 :       goto leave;
     534             :     }
     535         754 :   gpg->status.eof = 0;
     536             : 
     537         754 :   if (home_dir)
     538             :     {
     539         230 :       rc = add_arg (gpg, "--homedir");
     540         230 :       if (!rc)
     541         230 :         rc = add_arg (gpg, home_dir);
     542         230 :       if (rc)
     543           0 :         goto leave;
     544             :     }
     545             : 
     546         754 :   rc = add_arg (gpg, "--status-fd");
     547         754 :   if (rc)
     548           0 :     goto leave;
     549             : 
     550             :   {
     551             :     char buf[25];
     552         754 :     _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
     553         753 :     rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc);
     554         753 :     if (rc)
     555           0 :       goto leave;
     556             :   }
     557             : 
     558         753 :   rc = add_arg (gpg, "--no-tty");
     559         752 :   if (!rc)
     560         752 :     rc = add_arg (gpg, "--charset");
     561         753 :   if (!rc)
     562         754 :     rc = add_arg (gpg, "utf8");
     563         752 :   if (!rc)
     564         753 :     rc = add_arg (gpg, "--enable-progress-filter");
     565         750 :   if (!rc && have_gpg_version (gpg, "2.1.11"))
     566         751 :     rc = add_arg (gpg, "--exit-on-status-write-error");
     567         752 :   if (rc)
     568           0 :     goto leave;
     569             : 
     570         752 :   rc = _gpgme_getenv ("DISPLAY", &dft_display);
     571         752 :   if (rc)
     572           0 :     goto leave;
     573         752 :   if (dft_display)
     574             :     {
     575         753 :       rc = add_arg (gpg, "--display");
     576         754 :       if (!rc)
     577         752 :         rc = add_arg (gpg, dft_display);
     578             : 
     579         753 :       free (dft_display);
     580         753 :       if (rc)
     581           0 :         goto leave;
     582             :     }
     583             : 
     584         752 :   rc = _gpgme_getenv ("GPG_TTY", &env_tty);
     585         751 :   if (isatty (1) || env_tty || rc)
     586             :     {
     587         731 :       int err = 0;
     588             : 
     589         731 :       if (rc)
     590           0 :         goto leave;
     591         731 :       else if (env_tty)
     592             :         {
     593           0 :           snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
     594           0 :           free (env_tty);
     595             :         }
     596             :       else
     597         731 :         err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
     598             : 
     599             :       /* Even though isatty() returns 1, ttyname_r() may fail in many
     600             :          ways, e.g., when /dev/pts is not accessible under chroot.  */
     601         735 :       if (!err)
     602             :         {
     603         735 :           if (*dft_ttyname)
     604             :             {
     605         735 :               rc = add_arg (gpg, "--ttyname");
     606         734 :               if (!rc)
     607         734 :                 rc = add_arg (gpg, dft_ttyname);
     608             :             }
     609             :           else
     610           0 :             rc = 0;
     611         735 :           if (!rc)
     612             :             {
     613         734 :               rc = _gpgme_getenv ("TERM", &dft_ttytype);
     614         732 :               if (rc)
     615           0 :                 goto leave;
     616             : 
     617         732 :               if (dft_ttytype)
     618             :                 {
     619         732 :                   rc = add_arg (gpg, "--ttytype");
     620         732 :                   if (!rc)
     621         732 :                     rc = add_arg (gpg, dft_ttytype);
     622             :                 }
     623             : 
     624         733 :               free (dft_ttytype);
     625             :             }
     626         734 :           if (rc)
     627           0 :             goto leave;
     628             :         }
     629             :     }
     630             : 
     631         755 :   rc = gpgme_data_new (&gpg->diagnostics);
     632         754 :   if (rc)
     633           0 :     goto leave;
     634             : 
     635         754 :   rc = add_arg (gpg, "--logger-fd");
     636         754 :   if (rc)
     637           0 :     goto leave;
     638             : 
     639         754 :   rc = add_data (gpg, gpg->diagnostics, -2, 1);
     640             : 
     641             :  leave:
     642         754 :   if (rc)
     643           0 :     gpg_release (gpg);
     644             :   else
     645         754 :     *engine = gpg;
     646         754 :   return rc;
     647             : }
     648             : 
     649             : 
     650             : /* Copy flags from CTX into the engine object.  */
     651             : static void
     652         754 : gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
     653             : {
     654         754 :   engine_gpg_t gpg = engine;
     655             : 
     656         754 :   if (ctx->request_origin && have_gpg_version (gpg, "2.2.6"))
     657             :     {
     658          34 :       if (strlen (ctx->request_origin) + 1 > sizeof gpg->request_origin)
     659           0 :         strcpy (gpg->request_origin, "xxx"); /* Too long  - force error */
     660             :       else
     661          17 :         strcpy (gpg->request_origin, ctx->request_origin);
     662             :     }
     663             :   else
     664         737 :     *gpg->request_origin = 0;
     665             : 
     666         754 :   if (ctx->auto_key_locate && have_gpg_version (gpg, "2.1.18"))
     667             :     {
     668           0 :       if (gpg->auto_key_locate)
     669           0 :         free (gpg->auto_key_locate);
     670           0 :       gpg->auto_key_locate = _gpgme_strconcat ("--auto-key-locate=",
     671             :                                                ctx->auto_key_locate, NULL);
     672             :     }
     673             : 
     674         754 :   if (ctx->trust_model && strlen (ctx->trust_model))
     675             :     {
     676           0 :       if (gpg->trust_model)
     677           0 :         free (gpg->trust_model);
     678           0 :       gpg->trust_model = _gpgme_strconcat ("--trust-model=",
     679             :                                            ctx->trust_model, NULL);
     680             :     }
     681             : 
     682        1508 :   gpg->flags.no_symkey_cache = (ctx->no_symkey_cache
     683         754 :                                 && have_gpg_version (gpg, "2.2.7"));
     684         754 :   gpg->flags.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23"));
     685             : 
     686         754 :   gpg->flags.ignore_mdc_error = !!ctx->ignore_mdc_error;
     687             : 
     688         754 : }
     689             : 
     690             : 
     691             : static gpgme_error_t
     692        1508 : gpg_set_locale (void *engine, int category, const char *value)
     693             : {
     694        1508 :   engine_gpg_t gpg = engine;
     695             : 
     696             :   if (0)
     697             :     ;
     698             : #ifdef LC_CTYPE
     699        1508 :   else if (category == LC_CTYPE)
     700             :     {
     701         755 :       if (gpg->lc_ctype)
     702             :         {
     703           0 :           free (gpg->lc_ctype);
     704           0 :           gpg->lc_ctype = NULL;
     705             :         }
     706         755 :       if (value)
     707             :         {
     708         178 :           gpg->lc_ctype = strdup (value);
     709         178 :           if (!gpg->lc_ctype)
     710           0 :             return gpg_error_from_syserror ();
     711             :         }
     712             :     }
     713             : #endif
     714             : #ifdef LC_MESSAGES
     715         753 :   else if (category == LC_MESSAGES)
     716             :     {
     717         753 :       if (gpg->lc_messages)
     718             :         {
     719           0 :           free (gpg->lc_messages);
     720           0 :           gpg->lc_messages = NULL;
     721             :         }
     722         753 :       if (value)
     723             :         {
     724         177 :           gpg->lc_messages = strdup (value);
     725         177 :           if (!gpg->lc_messages)
     726           0 :             return gpg_error_from_syserror ();
     727             :         }
     728             :     }
     729             : #endif /* LC_MESSAGES */
     730             :   else
     731           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     732             : 
     733        1508 :   return 0;
     734             : }
     735             : 
     736             : /* This sets a status callback for monitoring status lines before they
     737             :  * are passed to a caller set handler.  */
     738             : static void
     739           4 : gpg_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
     740             : {
     741           4 :   engine_gpg_t gpg = engine;
     742             : 
     743           4 :   gpg->status.mon_cb = cb;
     744           4 :   gpg->status.mon_cb_value = cb_value;
     745           4 : }
     746             : 
     747             : 
     748             : /* Note, that the status_handler is allowed to modify the args
     749             :    value.  */
     750             : static void
     751         783 : gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
     752             :                         void *fnc_value)
     753             : {
     754         783 :   engine_gpg_t gpg = engine;
     755             : 
     756         783 :   gpg->status.fnc = fnc;
     757         783 :   gpg->status.fnc_value = fnc_value;
     758         783 : }
     759             : 
     760             : /* Kludge to process --with-colon output.  */
     761             : static gpgme_error_t
     762         344 : gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
     763             :                             void *fnc_value)
     764             : {
     765         344 :   engine_gpg_t gpg = engine;
     766             : 
     767         344 :   gpg->colon.bufsize = 1024;
     768         344 :   gpg->colon.readpos = 0;
     769         344 :   gpg->colon.buffer = malloc (gpg->colon.bufsize);
     770         344 :   if (!gpg->colon.buffer)
     771           0 :     return gpg_error_from_syserror ();
     772             : 
     773         344 :   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1)
     774             :     {
     775           0 :       int saved_err = gpg_error_from_syserror ();
     776           0 :       free (gpg->colon.buffer);
     777           0 :       gpg->colon.buffer = NULL;
     778           0 :       return saved_err;
     779             :     }
     780         344 :   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
     781         344 :       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
     782             :                                      close_notify_handler, gpg))
     783           0 :     return gpg_error (GPG_ERR_GENERAL);
     784         343 :   gpg->colon.eof = 0;
     785         343 :   gpg->colon.fnc = fnc;
     786         343 :   gpg->colon.fnc_value = fnc_value;
     787         343 :   return 0;
     788             : }
     789             : 
     790             : 
     791             : static gpgme_error_t
     792          84 : command_handler (void *opaque, int fd)
     793             : {
     794          84 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
     795          84 :   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
     796             :   gpgme_error_t err;
     797          84 :   int processed = 0;
     798          84 :   assert (gpg->cmd.used);
     799          84 :   assert (gpg->cmd.code);
     800          84 :   assert (gpg->cmd.fnc);
     801             : 
     802          84 :   err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd,
     803             :                       &processed);
     804             : 
     805          84 :   gpg->cmd.code = 0;
     806             :   /* And sleep again until read_status will wake us up again.  */
     807             :   /* XXX We must check if there are any more fds active after removing
     808             :      this one.  */
     809          84 :   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
     810          84 :   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
     811          84 :   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
     812             : 
     813          84 :   if (err)
     814           6 :     return err;
     815             : 
     816             :   /* We always need to send at least a newline character.  */
     817          78 :   if (!processed)
     818           0 :     _gpgme_io_write (fd, "\n", 1);
     819             : 
     820          78 :   return 0;
     821             : }
     822             : 
     823             : 
     824             : 
     825             : /* The FNC will be called to get a value for one of the commands with
     826             :  * a key KEY.  If the code passed to FNC is 0, the function may
     827             :  * release resources associated with the returned value from another
     828             :  * call.  To match such a second call to a first call, the returned
     829             :  * value from the first call is passed as keyword.  */
     830             : static gpgme_error_t
     831          99 : gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
     832             :                          void *fnc_value)
     833             : {
     834          99 :   engine_gpg_t gpg = engine;
     835             :   gpgme_error_t rc;
     836             : 
     837          99 :   rc = add_arg (gpg, "--command-fd");
     838          99 :   if (rc)
     839           0 :     return rc;
     840             : 
     841             :   /* This is a hack.  We don't have a real data object.  The only
     842             :      thing that matters is that we use something unique, so we use the
     843             :      address of the cmd structure in the gpg object.  */
     844          99 :   rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
     845          99 :   if (rc)
     846           0 :     return rc;
     847             : 
     848          99 :   gpg->cmd.fnc = fnc;
     849          99 :   gpg->cmd.cb_data = (void *) &gpg->cmd;
     850          99 :   gpg->cmd.fnc_value = fnc_value;
     851          99 :   gpg->cmd.used = 1;
     852          99 :   return 0;
     853             : }
     854             : 
     855             : 
     856             : static gpgme_error_t
     857         753 : build_argv (engine_gpg_t gpg, const char *pgmname)
     858             : {
     859             :   gpgme_error_t err;
     860             :   struct arg_and_data_s *a;
     861             :   struct fd_data_map_s *fd_data_map;
     862         753 :   size_t datac=0, argc=0;
     863             :   char **argv;
     864         753 :   int need_special = 0;
     865         753 :   int use_agent = 0;
     866             :   char *p;
     867             : 
     868         753 :   if (_gpgme_in_gpg_one_mode ())
     869             :     {
     870             :       /* In GnuPG-1 mode we don't want to use the agent with a
     871             :          malformed environment variable.  This is only a very basic
     872             :          test but sufficient to make our life in the regression tests
     873             :          easier.  With GnuPG-2 the agent is anyway required and on
     874             :          modern installations GPG_AGENT_INFO is optional.  */
     875           0 :       err = _gpgme_getenv ("GPG_AGENT_INFO", &p);
     876           0 :       if (err)
     877           0 :         return err;
     878           0 :       use_agent = (p && strchr (p, ':'));
     879           0 :       if (p)
     880           0 :         free (p);
     881             :     }
     882             : 
     883         754 :   if (gpg->argv)
     884             :     {
     885           0 :       free_argv (gpg->argv);
     886           0 :       gpg->argv = NULL;
     887             :     }
     888         754 :   if (gpg->fd_data_map)
     889             :     {
     890           0 :       free_fd_data_map (gpg->fd_data_map);
     891           0 :       gpg->fd_data_map = NULL;
     892             :     }
     893             : 
     894         754 :   argc++;       /* For argv[0].  */
     895       17711 :   for (a = gpg->arglist; a; a = a->next)
     896             :     {
     897       16957 :       argc++;
     898       16957 :       if (a->data)
     899             :         {
     900             :           /*fprintf (stderr, "build_argv: data\n" );*/
     901        1386 :           datac++;
     902        1386 :           if (a->dup_to == -1 && !a->print_fd)
     903         294 :             need_special = 1;
     904             :         }
     905             :       else
     906             :         {
     907             :           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
     908             :         }
     909             :     }
     910         754 :   if (need_special)
     911         268 :     argc++;
     912         754 :   if (use_agent)
     913           0 :     argc++;
     914         754 :   if (gpg->pinentry_mode)
     915          54 :     argc++;
     916         754 :   if (!gpg->cmd.used)
     917         655 :     argc++;     /* --batch */
     918         754 :   argc += 4;    /* --no-sk-comments, --request-origin, --no-symkey-cache */
     919             :                 /* --disable-dirmngr  */
     920             : 
     921         754 :   argv = calloc (argc + 1, sizeof *argv);
     922         754 :   if (!argv)
     923           0 :     return gpg_error_from_syserror ();
     924         754 :   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
     925         754 :   if (!fd_data_map)
     926             :     {
     927           0 :       int saved_err = gpg_error_from_syserror ();
     928           0 :       free_argv (argv);
     929           0 :       return saved_err;
     930             :     }
     931             : 
     932         754 :   argc = datac = 0;
     933         754 :   argv[argc] = strdup (_gpgme_get_basename (pgmname)); /* argv[0] */
     934         761 :   if (!argv[argc])
     935             :     {
     936           0 :       int saved_err = gpg_error_from_syserror ();
     937           0 :       free (fd_data_map);
     938           0 :       free_argv (argv);
     939           0 :       return saved_err;
     940             :     }
     941         761 :   argc++;
     942         761 :   if (need_special)
     943             :     {
     944         267 :       argv[argc] = strdup ("--enable-special-filenames");
     945         267 :       if (!argv[argc])
     946             :         {
     947           0 :           int saved_err = gpg_error_from_syserror ();
     948           0 :           free (fd_data_map);
     949           0 :           free_argv (argv);
     950           0 :           return saved_err;
     951             :         }
     952         267 :       argc++;
     953             :     }
     954         761 :   if (use_agent)
     955             :     {
     956           0 :       argv[argc] = strdup ("--use-agent");
     957           0 :       if (!argv[argc])
     958             :         {
     959           0 :           int saved_err = gpg_error_from_syserror ();
     960           0 :           free (fd_data_map);
     961           0 :           free_argv (argv);
     962           0 :           return saved_err;
     963             :         }
     964           0 :       argc++;
     965             :     }
     966             : 
     967         761 :   if (*gpg->request_origin)
     968             :     {
     969          34 :       argv[argc] = _gpgme_strconcat ("--request-origin=",
     970          17 :                                      gpg->request_origin, NULL);
     971          17 :       if (!argv[argc])
     972             :         {
     973           0 :           int saved_err = gpg_error_from_syserror ();
     974           0 :           free (fd_data_map);
     975           0 :           free_argv (argv);
     976           0 :           return saved_err;
     977             :         }
     978          17 :       argc++;
     979             :     }
     980             : 
     981         761 :   if (gpg->auto_key_locate)
     982             :     {
     983           0 :       argv[argc] = strdup (gpg->auto_key_locate);
     984           0 :       if (!argv[argc])
     985             :         {
     986           0 :           int saved_err = gpg_error_from_syserror ();
     987           0 :           free (fd_data_map);
     988           0 :           free_argv (argv);
     989           0 :           return saved_err;
     990             :         }
     991           0 :       argc++;
     992             :     }
     993             : 
     994         761 :   if (gpg->trust_model)
     995             :     {
     996           0 :       argv[argc] = strdup (gpg->trust_model);
     997           0 :       if (!argv[argc])
     998             :         {
     999           0 :           int saved_err = gpg_error_from_syserror ();
    1000           0 :           free (fd_data_map);
    1001           0 :           free_argv (argv);
    1002           0 :           return saved_err;
    1003             :         }
    1004           0 :       argc++;
    1005             :     }
    1006             : 
    1007         761 :   if (gpg->flags.no_symkey_cache)
    1008             :     {
    1009           0 :       argv[argc] = strdup ("--no-symkey-cache");
    1010           0 :       if (!argv[argc])
    1011             :         {
    1012           0 :           int saved_err = gpg_error_from_syserror ();
    1013           0 :           free (fd_data_map);
    1014           0 :           free_argv (argv);
    1015           0 :           return saved_err;
    1016             :         }
    1017           0 :       argc++;
    1018             :     }
    1019             : 
    1020         761 :   if (gpg->flags.ignore_mdc_error)
    1021             :     {
    1022           0 :       argv[argc] = strdup ("--ignore-mdc-error");
    1023           0 :       if (!argv[argc])
    1024             :         {
    1025           0 :           int saved_err = gpg_error_from_syserror ();
    1026           0 :           free (fd_data_map);
    1027           0 :           free_argv (argv);
    1028           0 :           return saved_err;
    1029             :         }
    1030           0 :       argc++;
    1031             :     }
    1032             : 
    1033         761 :   if (gpg->flags.offline)
    1034             :     {
    1035           0 :       argv[argc] = strdup ("--disable-dirmngr");
    1036           0 :       if (!argv[argc])
    1037             :         {
    1038           0 :           int saved_err = gpg_error_from_syserror ();
    1039           0 :           free (fd_data_map);
    1040           0 :           free_argv (argv);
    1041           0 :           return saved_err;
    1042             :         }
    1043           0 :       argc++;
    1044             :     }
    1045             : 
    1046         761 :   if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
    1047             :     {
    1048          54 :       const char *s = NULL;
    1049          54 :       switch (gpg->pinentry_mode)
    1050             :         {
    1051           0 :         case GPGME_PINENTRY_MODE_DEFAULT: break;
    1052           0 :         case GPGME_PINENTRY_MODE_ASK:     s = "--pinentry-mode=ask"; break;
    1053           0 :         case GPGME_PINENTRY_MODE_CANCEL:  s = "--pinentry-mode=cancel"; break;
    1054           0 :         case GPGME_PINENTRY_MODE_ERROR:   s = "--pinentry-mode=error"; break;
    1055          54 :         case GPGME_PINENTRY_MODE_LOOPBACK:s = "--pinentry-mode=loopback"; break;
    1056             :         }
    1057          54 :       if (s)
    1058             :         {
    1059          54 :           argv[argc] = strdup (s);
    1060          54 :           if (!argv[argc])
    1061             :             {
    1062           0 :               int saved_err = gpg_error_from_syserror ();
    1063           0 :               free (fd_data_map);
    1064           0 :               free_argv (argv);
    1065           0 :               return saved_err;
    1066             :             }
    1067          54 :           argc++;
    1068             :         }
    1069             :     }
    1070             : 
    1071         761 :   if (!gpg->cmd.used)
    1072             :     {
    1073         654 :       argv[argc] = strdup ("--batch");
    1074         654 :       if (!argv[argc])
    1075             :         {
    1076           0 :           int saved_err = gpg_error_from_syserror ();
    1077           0 :           free (fd_data_map);
    1078           0 :           free_argv (argv);
    1079           0 :           return saved_err;
    1080             :         }
    1081         654 :       argc++;
    1082             :     }
    1083         761 :   argv[argc] = strdup ("--no-sk-comments");
    1084         761 :   if (!argv[argc])
    1085             :     {
    1086           0 :       int saved_err = gpg_error_from_syserror ();
    1087           0 :       free (fd_data_map);
    1088           0 :       free_argv (argv);
    1089           0 :       return saved_err;
    1090             :     }
    1091         761 :   argc++;
    1092       17709 :   for (a = gpg->arglist; a; a = a->next)
    1093             :     {
    1094       16955 :       if (a->arg_locp)
    1095         754 :         *(a->arg_locp) = argc;
    1096             : 
    1097       16955 :       if (a->data)
    1098             :         {
    1099             :           /* Create a pipe to pass it down to gpg.  */
    1100        1389 :           fd_data_map[datac].inbound = a->inbound;
    1101             : 
    1102             :           /* Create a pipe.  */
    1103             :           {
    1104             :             int fds[2];
    1105             : 
    1106        1389 :             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
    1107             :                 == -1)
    1108             :               {
    1109           0 :                 int saved_err = gpg_error_from_syserror ();
    1110           0 :                 free (fd_data_map);
    1111           0 :                 free_argv (argv);
    1112           0 :                 return saved_err;
    1113             :               }
    1114        1384 :             if (_gpgme_io_set_close_notify (fds[0],
    1115             :                                             close_notify_handler, gpg)
    1116        1386 :                 || _gpgme_io_set_close_notify (fds[1],
    1117             :                                                close_notify_handler,
    1118             :                                                gpg))
    1119             :               {
    1120             :                 /* We leak fd_data_map and the fds.  This is not easy
    1121             :                    to avoid and given that we reach this here only
    1122             :                    after a malloc failure for a small object, it is
    1123             :                    probably better not to do anything.  */
    1124           4 :                 return gpg_error (GPG_ERR_GENERAL);
    1125             :               }
    1126             :             /* If the data_type is FD, we have to do a dup2 here.  */
    1127        1382 :             if (fd_data_map[datac].inbound)
    1128             :               {
    1129         989 :                 fd_data_map[datac].fd       = fds[0];
    1130         989 :                 fd_data_map[datac].peer_fd  = fds[1];
    1131             :               }
    1132             :             else
    1133             :               {
    1134         393 :                 fd_data_map[datac].fd       = fds[1];
    1135         393 :                 fd_data_map[datac].peer_fd  = fds[0];
    1136             :               }
    1137             :           }
    1138             : 
    1139             :           /* Hack to get hands on the fd later.  */
    1140        1382 :           if (gpg->cmd.used)
    1141             :             {
    1142         373 :               if (gpg->cmd.cb_data == a->data)
    1143             :                 {
    1144          99 :                   assert (gpg->cmd.idx == -1);
    1145          99 :                   gpg->cmd.idx = datac;
    1146             :                 }
    1147             :             }
    1148             : 
    1149        1382 :           fd_data_map[datac].data = a->data;
    1150        1382 :           fd_data_map[datac].dup_to = a->dup_to;
    1151             : 
    1152        1382 :           if (a->dup_to == -1)
    1153             :             {
    1154             :               char *ptr;
    1155        1147 :               int buflen = 25;
    1156             : 
    1157        1147 :               argv[argc] = malloc (buflen);
    1158        1147 :               if (!argv[argc])
    1159             :                 {
    1160           0 :                   int saved_err = gpg_error_from_syserror ();
    1161           0 :                   free (fd_data_map);
    1162           0 :                   free_argv (argv);
    1163           0 :                   return saved_err;
    1164             :                 }
    1165             : 
    1166        1147 :               ptr = argv[argc];
    1167        1147 :               if (!a->print_fd)
    1168             :                 {
    1169         294 :                   *(ptr++) = '-';
    1170         294 :                   *(ptr++) = '&';
    1171         294 :                   buflen -= 2;
    1172             :                 }
    1173             : 
    1174        1147 :               _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
    1175        1147 :               fd_data_map[datac].arg_loc = argc;
    1176        1147 :               argc++;
    1177             :             }
    1178        1382 :           datac++;
    1179             :         }
    1180             :       else
    1181             :         {
    1182       15566 :           argv[argc] = strdup (a->arg);
    1183       15566 :           if (!argv[argc])
    1184             :             {
    1185           0 :               int saved_err = gpg_error_from_syserror ();
    1186           0 :               free (fd_data_map);
    1187           0 :               free_argv (argv);
    1188           0 :               return saved_err;
    1189             :             }
    1190       15566 :             argc++;
    1191             :         }
    1192             :     }
    1193             : 
    1194         754 :   gpg->argv = argv;
    1195         754 :   gpg->fd_data_map = fd_data_map;
    1196         754 :   return 0;
    1197             : }
    1198             : 
    1199             : 
    1200             : static gpgme_error_t
    1201        2421 : add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
    1202             :            void **tag)
    1203             : {
    1204             :   gpgme_error_t err;
    1205             : 
    1206        2421 :   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
    1207        2420 :   if (err)
    1208           0 :     return err;
    1209        2420 :   if (!dir)
    1210             :     /* FIXME Kludge around poll() problem.  */
    1211         372 :     err = _gpgme_io_set_nonblocking (fd);
    1212        2420 :   return err;
    1213             : }
    1214             : 
    1215             : 
    1216             : /* Handle the status output of GnuPG.  This function does read entire
    1217             :    lines and passes them as C strings to the callback function (we can
    1218             :    use C Strings because the status output is always UTF-8 encoded).
    1219             :    Of course we have to buffer the lines to cope with long lines
    1220             :    e.g. with a large user ID.  Note: We can optimize this to only cope
    1221             :    with status line code we know about and skip all other stuff
    1222             :    without buffering (i.e. without extending the buffer).  */
    1223             : static gpgme_error_t
    1224        5310 : read_status (engine_gpg_t gpg)
    1225             : {
    1226             :   char *p;
    1227             :   int nread;
    1228        5310 :   size_t bufsize = gpg->status.bufsize;
    1229        5310 :   char *buffer = gpg->status.buffer;
    1230        5310 :   size_t readpos = gpg->status.readpos;
    1231             :   gpgme_error_t err;
    1232             : 
    1233        5310 :   assert (buffer);
    1234        5310 :   if (bufsize - readpos < 256)
    1235             :     {
    1236             :       /* Need more room for the read.  */
    1237           0 :       bufsize += 1024;
    1238           0 :       buffer = realloc (buffer, bufsize);
    1239           0 :       if (!buffer)
    1240           0 :         return gpg_error_from_syserror ();
    1241             :     }
    1242             : 
    1243       10620 :   nread = _gpgme_io_read (gpg->status.fd[0],
    1244        5310 :                           buffer + readpos, bufsize-readpos);
    1245        5308 :   if (nread == -1)
    1246           0 :     return gpg_error_from_syserror ();
    1247             : 
    1248        5308 :   if (!nread)
    1249             :     {
    1250         729 :       err = 0;
    1251         729 :       gpg->status.eof = 1;
    1252         729 :       if (gpg->status.mon_cb)
    1253           2 :         err = gpg->status.mon_cb (gpg->status.mon_cb_value, "", "");
    1254         729 :       if (gpg->status.fnc)
    1255             :         {
    1256         729 :           char emptystring[1] = {0};
    1257         729 :           err = gpg->status.fnc (gpg->status.fnc_value,
    1258             :                                  GPGME_STATUS_EOF, emptystring);
    1259         729 :           if (gpg_err_code (err) == GPG_ERR_FALSE)
    1260           0 :             err = 0; /* Drop special error code.  */
    1261             :         }
    1262             : 
    1263         729 :       return err;
    1264             :     }
    1265             : 
    1266       14589 :   while (nread > 0)
    1267             :     {
    1268      244340 :       for (p = buffer + readpos; nread; nread--, p++)
    1269             :         {
    1270      244338 :           if (*p == '\n')
    1271             :             {
    1272             :               /* (we require that the last line is terminated by a LF) */
    1273        5440 :               if (p > buffer && p[-1] == '\r')
    1274           0 :                 p[-1] = 0;
    1275        5440 :               *p = 0;
    1276        5440 :               if (!strncmp (buffer, "[GNUPG:] ", 9)
    1277        5442 :                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
    1278             :                 {
    1279             :                   char *rest;
    1280             :                   gpgme_status_code_t r;
    1281             : 
    1282        5440 :                   rest = strchr (buffer + 9, ' ');
    1283        5440 :                   if (!rest)
    1284         409 :                     rest = p; /* Set to an empty string.  */
    1285             :                   else
    1286        5031 :                     *rest++ = 0;
    1287             : 
    1288        5440 :                   r = _gpgme_parse_status (buffer + 9);
    1289        5443 :                   if (gpg->status.mon_cb && r != GPGME_STATUS_PROGRESS)
    1290             :                     {
    1291             :                       /* Note that we call the monitor even if we do
    1292             :                        * not know the status code (r < 0).  */
    1293          16 :                       err = gpg->status.mon_cb (gpg->status.mon_cb_value,
    1294           8 :                                                 buffer + 9, rest);
    1295           8 :                       if (err)
    1296           2 :                         return err;
    1297             :                     }
    1298             :                   if (r >= 0)
    1299             :                     {
    1300        5441 :                       if (gpg->cmd.used
    1301        1206 :                           && (r == GPGME_STATUS_GET_BOOL
    1302        1198 :                               || r == GPGME_STATUS_GET_LINE
    1303        1154 :                               || r == GPGME_STATUS_GET_HIDDEN))
    1304             :                         {
    1305          84 :                           gpg->cmd.code = r;
    1306          84 :                           if (gpg->cmd.keyword)
    1307          41 :                             free (gpg->cmd.keyword);
    1308          84 :                           gpg->cmd.keyword = strdup (rest);
    1309          84 :                           if (!gpg->cmd.keyword)
    1310           0 :                             return gpg_error_from_syserror ();
    1311             :                           /* This should be the last thing we have
    1312             :                              received and the next thing will be that
    1313             :                              the command handler does its action.  */
    1314          84 :                           if (nread > 1)
    1315           0 :                             TRACE0 (DEBUG_CTX, "gpgme:read_status", 0,
    1316             :                                     "error: unexpected data");
    1317             : 
    1318          84 :                           add_io_cb (gpg, gpg->cmd.fd, 0,
    1319             :                                      command_handler, gpg,
    1320          84 :                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
    1321          84 :                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
    1322          84 :                           gpg->cmd.fd = -1;
    1323             :                         }
    1324        5357 :                       else if (gpg->status.fnc)
    1325             :                         {
    1326        5358 :                           err = gpg->status.fnc (gpg->status.fnc_value,
    1327             :                                                  r, rest);
    1328        5354 :                           if (gpg_err_code (err) == GPG_ERR_FALSE)
    1329           0 :                             err = 0; /* Drop special error code.  */
    1330        5356 :                           if (err)
    1331          10 :                             return err;
    1332             :                         }
    1333             :                     }
    1334             :                 }
    1335             :               /* To reuse the buffer for the next line we have to
    1336             :                  shift the remaining data to the buffer start and
    1337             :                  restart the loop Hmmm: We can optimize this function
    1338             :                  by looking forward in the buffer to see whether a
    1339             :                  second complete line is available and in this case
    1340             :                  avoid the memmove for this line.  */
    1341        5429 :               nread--; p++;
    1342        5429 :               if (nread)
    1343         861 :                 memmove (buffer, p, nread);
    1344        5429 :               readpos = 0;
    1345        5429 :               break; /* the for loop */
    1346             :             }
    1347             :           else
    1348      238898 :             readpos++;
    1349             :         }
    1350             :     }
    1351             : 
    1352             :   /* Update the gpg object.  */
    1353        4568 :   gpg->status.bufsize = bufsize;
    1354        4568 :   gpg->status.buffer = buffer;
    1355        4568 :   gpg->status.readpos = readpos;
    1356        4568 :   return 0;
    1357             : }
    1358             : 
    1359             : 
    1360             : static gpgme_error_t
    1361        5310 : status_handler (void *opaque, int fd)
    1362             : {
    1363        5310 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
    1364        5310 :   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
    1365             :   int err;
    1366             : 
    1367        5310 :   assert (fd == gpg->status.fd[0]);
    1368        5310 :   err = read_status (gpg);
    1369        5308 :   if (err)
    1370          24 :     return err;
    1371        5284 :   if (gpg->status.eof)
    1372         717 :     _gpgme_io_close (fd);
    1373        5283 :   return 0;
    1374             : }
    1375             : 
    1376             : 
    1377             : static gpgme_error_t
    1378        1026 : read_colon_line (engine_gpg_t gpg)
    1379             : {
    1380             :   char *p;
    1381             :   int nread;
    1382        1026 :   size_t bufsize = gpg->colon.bufsize;
    1383        1026 :   char *buffer = gpg->colon.buffer;
    1384        1026 :   size_t readpos = gpg->colon.readpos;
    1385             : 
    1386        1026 :   assert (buffer);
    1387        1026 :   if (bufsize - readpos < 256)
    1388             :     {
    1389             :       /* Need more room for the read.  */
    1390           0 :       bufsize += 1024;
    1391           0 :       buffer = realloc (buffer, bufsize);
    1392           0 :       if (!buffer)
    1393           0 :         return gpg_error_from_syserror ();
    1394             :     }
    1395             : 
    1396        1026 :   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
    1397        2628 :   if (nread == -1)
    1398           0 :     return gpg_error_from_syserror ();
    1399             : 
    1400        2628 :   if (!nread)
    1401             :     {
    1402         333 :       gpg->colon.eof = 1;
    1403         333 :       assert (gpg->colon.fnc);
    1404         333 :       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
    1405         332 :       return 0;
    1406             :     }
    1407             : 
    1408        9167 :   while (nread > 0)
    1409             :     {
    1410      524221 :       for (p = buffer + readpos; nread; nread--, p++)
    1411             :         {
    1412      525585 :           if ( *p == '\n' )
    1413             :             {
    1414             :               /* (we require that the last line is terminated by a LF)
    1415             :                  and we skip empty lines.  Note: we use UTF8 encoding
    1416             :                  and escaping of special characters.  We require at
    1417             :                  least one colon to cope with some other printed
    1418             :                  information.  */
    1419        7549 :               *p = 0;
    1420        7549 :               if (*buffer && strchr (buffer, ':'))
    1421             :                 {
    1422        7548 :                   char *line = NULL;
    1423             : 
    1424        7548 :                   if (gpg->colon.preprocess_fnc)
    1425             :                     {
    1426             :                       gpgme_error_t err;
    1427             : 
    1428        1603 :                       err = gpg->colon.preprocess_fnc (buffer, &line);
    1429           0 :                       if (err)
    1430           0 :                         return err;
    1431             :                     }
    1432             : 
    1433        5945 :                   assert (gpg->colon.fnc);
    1434        5945 :                   if (line)
    1435             :                     {
    1436           0 :                       char *linep = line;
    1437             :                       char *endp;
    1438             : 
    1439             :                       do
    1440             :                         {
    1441           0 :                           endp = strchr (linep, '\n');
    1442           0 :                           if (endp)
    1443           0 :                             *endp++ = 0;
    1444           0 :                           gpg->colon.fnc (gpg->colon.fnc_value, linep);
    1445           0 :                           linep = endp;
    1446             :                         }
    1447           0 :                       while (linep && *linep);
    1448             : 
    1449           0 :                       gpgrt_free (line);
    1450             :                     }
    1451             :                   else
    1452        5945 :                     gpg->colon.fnc (gpg->colon.fnc_value, buffer);
    1453             :                 }
    1454             : 
    1455             :               /* To reuse the buffer for the next line we have to
    1456             :                  shift the remaining data to the buffer start and
    1457             :                  restart the loop Hmmm: We can optimize this function
    1458             :                  by looking forward in the buffer to see whether a
    1459             :                  second complete line is available and in this case
    1460             :                  avoid the memmove for this line.  */
    1461        5941 :               nread--; p++;
    1462        5941 :               if (nread)
    1463        5496 :                 memmove (buffer, p, nread);
    1464        5941 :               readpos = 0;
    1465        5941 :               break; /* The for loop.  */
    1466             :             }
    1467             :           else
    1468      518036 :             readpos++;
    1469             :         }
    1470             :     }
    1471             : 
    1472             :   /* Update the gpg object.  */
    1473         687 :   gpg->colon.bufsize = bufsize;
    1474         687 :   gpg->colon.buffer  = buffer;
    1475         687 :   gpg->colon.readpos = readpos;
    1476         687 :   return 0;
    1477             : }
    1478             : 
    1479             : 
    1480             : /* This colonline handler thing is not the clean way to do it.  It
    1481             :    might be better to enhance the gpgme_data_t object to act as a wrapper
    1482             :    for a callback.  Same goes for the status thing.  For now we use
    1483             :    this thing here because it is easier to implement.  */
    1484             : static gpgme_error_t
    1485        1026 : colon_line_handler (void *opaque, int fd)
    1486             : {
    1487        1026 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
    1488        1026 :   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
    1489        1026 :   gpgme_error_t rc = 0;
    1490             : 
    1491        1026 :   assert (fd == gpg->colon.fd[0]);
    1492        1026 :   rc = read_colon_line (gpg);
    1493        1019 :   if (rc)
    1494           0 :     return rc;
    1495        1019 :   if (gpg->colon.eof)
    1496         332 :     _gpgme_io_close (fd);
    1497        1019 :   return 0;
    1498             : }
    1499             : 
    1500             : 
    1501             : static gpgme_error_t
    1502         751 : start (engine_gpg_t gpg)
    1503             : {
    1504             :   gpgme_error_t rc;
    1505             :   int i, n;
    1506             :   int status;
    1507             :   struct spawn_fd_item_s *fd_list;
    1508             :   pid_t pid;
    1509             :   const char *pgmname;
    1510             : 
    1511         751 :   if (!gpg)
    1512           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    1513             : 
    1514         751 :   if (!gpg->file_name && !_gpgme_get_default_gpg_name ())
    1515           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
    1516             : 
    1517         751 :   if (gpg->lc_ctype)
    1518             :     {
    1519         178 :       rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
    1520         177 :       if (!rc)
    1521         177 :         rc = add_arg_ext (gpg, "--lc-ctype", 1);
    1522         180 :       if (rc)
    1523           0 :         return rc;
    1524             :     }
    1525             : 
    1526         753 :   if (gpg->lc_messages)
    1527             :     {
    1528         177 :       rc = add_arg_ext (gpg, gpg->lc_messages, 1);
    1529         177 :       if (!rc)
    1530         177 :         rc = add_arg_ext (gpg, "--lc-messages", 1);
    1531         176 :       if (rc)
    1532           0 :         return rc;
    1533             :     }
    1534             : 
    1535         752 :   pgmname = gpg->file_name ? gpg->file_name : _gpgme_get_default_gpg_name ();
    1536         752 :   rc = build_argv (gpg, pgmname);
    1537         754 :   if (rc)
    1538           0 :     return rc;
    1539             : 
    1540             :   /* status_fd, colon_fd and end of list.  */
    1541         754 :   n = 3;
    1542        2140 :   for (i = 0; gpg->fd_data_map[i].data; i++)
    1543        1386 :     n++;
    1544         754 :   fd_list = calloc (n, sizeof *fd_list);
    1545         754 :   if (! fd_list)
    1546           0 :     return gpg_error_from_syserror ();
    1547             : 
    1548             :   /* Build the fd list for the child.  */
    1549         754 :   n = 0;
    1550         754 :   fd_list[n].fd = gpg->status.fd[1];
    1551         754 :   fd_list[n].dup_to = -1;
    1552         754 :   fd_list[n].arg_loc = gpg->status.arg_loc;
    1553         754 :   n++;
    1554         754 :   if (gpg->colon.fnc)
    1555             :     {
    1556         344 :       fd_list[n].fd = gpg->colon.fd[1];
    1557         344 :       fd_list[n].dup_to = 1;
    1558         344 :       n++;
    1559             :     }
    1560        2140 :   for (i = 0; gpg->fd_data_map[i].data; i++)
    1561             :     {
    1562        1386 :       fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
    1563        1386 :       fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
    1564        1386 :       fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
    1565        1386 :       n++;
    1566             :     }
    1567         754 :   fd_list[n].fd = -1;
    1568         754 :   fd_list[n].dup_to = -1;
    1569             : 
    1570         754 :   status = _gpgme_io_spawn (pgmname, gpg->argv,
    1571             :                             (IOSPAWN_FLAG_DETACHED |IOSPAWN_FLAG_ALLOW_SET_FG),
    1572             :                             fd_list, NULL, NULL, &pid);
    1573             :   {
    1574         740 :     int saved_err = gpg_error_from_syserror ();
    1575         740 :     free (fd_list);
    1576         740 :     if (status == -1)
    1577           0 :       return saved_err;
    1578             :   }
    1579             : 
    1580             :   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
    1581             : 
    1582         740 :   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
    1583             :                   &gpg->status.tag);
    1584         739 :   if (rc)
    1585             :     /* FIXME: kill the child */
    1586           0 :     return rc;
    1587             : 
    1588         739 :   if (gpg->colon.fnc)
    1589             :     {
    1590         333 :       assert (gpg->colon.fd[0] != -1);
    1591         333 :       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
    1592             :                       &gpg->colon.tag);
    1593         333 :       if (rc)
    1594             :         /* FIXME: kill the child */
    1595           0 :         return rc;
    1596             :     }
    1597             : 
    1598        2100 :   for (i = 0; gpg->fd_data_map[i].data; i++)
    1599             :     {
    1600        1361 :       if (gpg->cmd.used && i == gpg->cmd.idx)
    1601             :         {
    1602             :           /* Park the cmd fd.  */
    1603          97 :           gpg->cmd.fd = gpg->fd_data_map[i].fd;
    1604          97 :           gpg->fd_data_map[i].fd = -1;
    1605             :         }
    1606             :       else
    1607             :         {
    1608        3792 :           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
    1609        1264 :                           gpg->fd_data_map[i].inbound,
    1610        1264 :                           gpg->fd_data_map[i].inbound
    1611             :                           ? _gpgme_data_inbound_handler
    1612             :                           : _gpgme_data_outbound_handler,
    1613        2528 :                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
    1614             : 
    1615        1264 :           if (rc)
    1616             :             /* FIXME: kill the child */
    1617           0 :             return rc;
    1618             :         }
    1619             :     }
    1620             : 
    1621         739 :   gpg_io_event (gpg, GPGME_EVENT_START, NULL);
    1622             : 
    1623             :   /* fixme: check what data we can release here */
    1624         739 :   return 0;
    1625             : }
    1626             : 
    1627             : 
    1628             : /* Add the --input-size-hint option if requested.  */
    1629             : static gpgme_error_t
    1630         241 : add_input_size_hint (engine_gpg_t gpg, gpgme_data_t data)
    1631             : {
    1632             :   gpgme_error_t err;
    1633         241 :   gpgme_off_t value = _gpgme_data_get_size_hint (data);
    1634             :   char numbuf[50];  /* Large enough for even 2^128 in base-10.  */
    1635             :   char *p;
    1636             : 
    1637         242 :   if (!value || !have_gpg_version (gpg, "2.1.15"))
    1638         216 :     return 0;
    1639             : 
    1640          26 :   err = add_arg (gpg, "--input-size-hint");
    1641          26 :   if (!err)
    1642             :     {
    1643          26 :       p = numbuf + sizeof numbuf;
    1644          26 :       *--p = 0;
    1645             :       do
    1646             :         {
    1647          67 :           *--p = '0' + (value % 10);
    1648          67 :           value /= 10;
    1649             :         }
    1650          67 :       while (value);
    1651          26 :       err = add_arg (gpg, p);
    1652             :     }
    1653          26 :   return err;
    1654             : }
    1655             : 
    1656             : 
    1657             : static gpgme_error_t
    1658          54 : gpg_decrypt (void *engine,
    1659             :              gpgme_decrypt_flags_t flags,
    1660             :              gpgme_data_t ciph, gpgme_data_t plain,
    1661             :              int export_session_key, const char *override_session_key,
    1662             :              int auto_key_retrieve)
    1663             : {
    1664          54 :   engine_gpg_t gpg = engine;
    1665             :   gpgme_error_t err;
    1666             : 
    1667          54 :   err = add_arg (gpg, "--decrypt");
    1668             : 
    1669          54 :   if (!err && (flags & GPGME_DECRYPT_UNWRAP))
    1670             :     {
    1671           1 :       if (!have_gpg_version (gpg, "2.1.12"))
    1672           0 :         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
    1673             :       else
    1674           1 :         err = add_arg (gpg, "--unwrap");
    1675             :     }
    1676             : 
    1677          54 :   if (!err && export_session_key)
    1678           0 :     err = add_arg (gpg, "--show-session-key");
    1679             : 
    1680          54 :   if (!err && auto_key_retrieve)
    1681           0 :     err = add_arg (gpg, "--auto-key-retrieve");
    1682             : 
    1683          54 :   if (!err && override_session_key && *override_session_key)
    1684             :     {
    1685           0 :       if (have_gpg_version (gpg, "2.1.16"))
    1686             :         {
    1687           0 :           gpgme_data_release (gpg->override_session_key);
    1688           0 :           TRACE2 (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n",
    1689             :                   override_session_key,
    1690             :                   strlen (override_session_key));
    1691             : 
    1692           0 :           err = gpgme_data_new_from_mem (&gpg->override_session_key,
    1693             :                                          override_session_key,
    1694             :                                          strlen (override_session_key), 1);
    1695           0 :           if (!err)
    1696             :             {
    1697             :               /* We add --no-keyring because a keyring is not required
    1698             :                * when we are overriding the session key.  It would
    1699             :                * work without that option but --no-keyring avoids that
    1700             :                * gpg return a failure due to a missing key log_error()
    1701             :                * diagnostic.  --no-keyring is supported since 2.1.14. */
    1702           0 :               err = add_arg (gpg, "--no-keyring");
    1703           0 :               if (!err)
    1704           0 :                 err = add_arg (gpg, "--override-session-key-fd");
    1705           0 :               if (!err)
    1706           0 :                 err = add_data (gpg, gpg->override_session_key, -2, 0);
    1707             :             }
    1708             :         }
    1709             :       else
    1710             :         {
    1711             :           /* Using that option may leak the session key via ps(1).  */
    1712           0 :           err = add_arg (gpg, "--override-session-key");
    1713           0 :           if (!err)
    1714           0 :             err = add_arg (gpg, override_session_key);
    1715             :         }
    1716             :     }
    1717             : 
    1718             :   /* Tell the gpg object about the data.  */
    1719          54 :   if (!err)
    1720          54 :     err = add_arg (gpg, "--output");
    1721          54 :   if (!err)
    1722          54 :     err = add_arg (gpg, "-");
    1723          54 :   if (!err)
    1724          54 :     err = add_data (gpg, plain, 1, 1);
    1725          54 :   if (!err)
    1726          54 :     err = add_input_size_hint (gpg, ciph);
    1727          54 :   if (!err)
    1728          54 :     err = add_arg (gpg, "--");
    1729          54 :   if (!err)
    1730          54 :     err = add_data (gpg, ciph, -1, 0);
    1731             : 
    1732          54 :   if (!err)
    1733          54 :     err = start (gpg);
    1734          52 :   return err;
    1735             : }
    1736             : 
    1737             : static gpgme_error_t
    1738           1 : gpg_delete (void *engine, gpgme_key_t key, unsigned int flags)
    1739             : {
    1740           1 :   engine_gpg_t gpg = engine;
    1741           1 :   gpgme_error_t err = 0;
    1742           1 :   int allow_secret = flags & GPGME_DELETE_ALLOW_SECRET;
    1743           1 :   int force = flags & GPGME_DELETE_FORCE;
    1744             : 
    1745           1 :   if (force)
    1746           0 :     err = add_arg (gpg, "--yes");
    1747           1 :   if (!err)
    1748           1 :     err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
    1749             :                    : "--delete-key");
    1750           1 :   if (!err)
    1751           1 :     err = add_arg (gpg, "--");
    1752           1 :   if (!err)
    1753             :     {
    1754           1 :       if (!key->subkeys || !key->subkeys->fpr)
    1755           0 :         return gpg_error (GPG_ERR_INV_VALUE);
    1756             :       else
    1757           1 :         err = add_arg (gpg, key->subkeys->fpr);
    1758             :     }
    1759             : 
    1760           1 :   if (!err)
    1761           1 :     err = start (gpg);
    1762           1 :   return err;
    1763             : }
    1764             : 
    1765             : 
    1766             : static gpgme_error_t
    1767           0 : gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags)
    1768             : {
    1769           0 :   engine_gpg_t gpg = engine;
    1770             :   gpgme_error_t err;
    1771             : 
    1772             :   (void)flags;
    1773             : 
    1774           0 :   if (!key || !key->subkeys || !key->subkeys->fpr)
    1775           0 :     return gpg_error (GPG_ERR_INV_CERT_OBJ);
    1776             : 
    1777           0 :   err = add_arg (gpg, "--passwd");
    1778           0 :   if (!err)
    1779           0 :     err = add_arg (gpg, key->subkeys->fpr);
    1780           0 :   if (!err)
    1781           0 :     err = start (gpg);
    1782           0 :   return err;
    1783             : }
    1784             : 
    1785             : 
    1786             : static gpgme_error_t
    1787          86 : append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
    1788             : {
    1789          86 :   gpgme_error_t err = 0;
    1790             :   int i;
    1791             :   gpgme_key_t key;
    1792             : 
    1793         143 :   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
    1794             :     {
    1795          57 :       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
    1796          57 :       if (s)
    1797             :         {
    1798          57 :           if (!err)
    1799          57 :             err = add_arg (gpg, "-u");
    1800          57 :           if (!err)
    1801          57 :             err = add_arg (gpg, s);
    1802             :         }
    1803          57 :       gpgme_key_unref (key);
    1804          57 :       if (err)
    1805           0 :         break;
    1806             :     }
    1807          86 :   return err;
    1808             : }
    1809             : 
    1810             : 
    1811             : static gpgme_error_t
    1812         122 : append_args_from_sender (engine_gpg_t gpg, gpgme_ctx_t ctx)
    1813             : {
    1814             :   gpgme_error_t err;
    1815             : 
    1816         122 :   if (ctx->sender && have_gpg_version (gpg, "2.1.15"))
    1817             :     {
    1818           2 :       err = add_arg (gpg, "--sender");
    1819           5 :       if (!err)
    1820           2 :         err = add_arg (gpg, ctx->sender);
    1821             :     }
    1822             :   else
    1823         120 :     err = 0;
    1824         123 :   return err;
    1825             : }
    1826             : 
    1827             : 
    1828             : static gpgme_error_t
    1829          65 : append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
    1830             : {
    1831          65 :   gpgme_error_t err = 0;
    1832             :   gpgme_sig_notation_t notation;
    1833             : 
    1834          65 :   notation = gpgme_sig_notation_get (ctx);
    1835             : 
    1836         139 :   while (!err && notation)
    1837             :     {
    1838           9 :       if (notation->name
    1839           6 :           && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
    1840           0 :         err = gpg_error (GPG_ERR_INV_VALUE);
    1841           9 :       else if (notation->name)
    1842             :         {
    1843             :           char *arg;
    1844             : 
    1845             :           /* Maximum space needed is one byte for the "critical" flag,
    1846             :              the name, one byte for '=', the value, and a terminating
    1847             :              '\0'.  */
    1848             : 
    1849           6 :           arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
    1850           6 :           if (!arg)
    1851           0 :             err = gpg_error_from_syserror ();
    1852             : 
    1853           6 :           if (!err)
    1854             :             {
    1855           6 :               char *argp = arg;
    1856             : 
    1857           6 :               if (notation->critical)
    1858           3 :                 *(argp++) = '!';
    1859             : 
    1860           6 :               memcpy (argp, notation->name, notation->name_len);
    1861           6 :               argp += notation->name_len;
    1862             : 
    1863           6 :               *(argp++) = '=';
    1864             : 
    1865             :               /* We know that notation->name is '\0' terminated.  */
    1866           6 :               strcpy (argp, notation->value);
    1867             :             }
    1868             : 
    1869           6 :           if (!err)
    1870           6 :             err = add_arg (gpg, "--sig-notation");
    1871           6 :           if (!err)
    1872           6 :             err = add_arg (gpg, arg);
    1873             : 
    1874           6 :           if (arg)
    1875           6 :             free (arg);
    1876             :         }
    1877             :       else
    1878             :         {
    1879             :           /* This is a policy URL.  */
    1880             : 
    1881             :           char *value;
    1882             : 
    1883           3 :           if (notation->critical)
    1884             :             {
    1885           0 :               value = malloc (1 + notation->value_len + 1);
    1886           0 :               if (!value)
    1887           0 :                 err = gpg_error_from_syserror ();
    1888             :               else
    1889             :                 {
    1890           0 :                   value[0] = '!';
    1891             :                   /* We know that notation->value is '\0' terminated.  */
    1892           0 :                   strcpy (&value[1], notation->value);
    1893             :                 }
    1894             :             }
    1895             :           else
    1896           3 :             value = notation->value;
    1897             : 
    1898           3 :           if (!err)
    1899           3 :             err = add_arg (gpg, "--sig-policy-url");
    1900           3 :           if (!err)
    1901           3 :             err = add_arg (gpg, value);
    1902             : 
    1903           3 :           if (value != notation->value)
    1904           0 :             free (value);
    1905             :         }
    1906             : 
    1907           9 :       notation = notation->next;
    1908             :     }
    1909          65 :   return err;
    1910             : }
    1911             : 
    1912             : 
    1913             : static gpgme_error_t
    1914          13 : gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
    1915             :           gpgme_ctx_t ctx /* FIXME */)
    1916             : {
    1917          13 :   engine_gpg_t gpg = engine;
    1918             :   gpgme_error_t err;
    1919             : 
    1920          13 :   err = add_arg (gpg, "--with-colons");
    1921          13 :   if (!err)
    1922          13 :     err = append_args_from_signers (gpg, ctx);
    1923          13 :   if (!err)
    1924          13 :   err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
    1925          13 :   if (!err)
    1926          13 :     err = add_data (gpg, out, 1, 1);
    1927          13 :   if (!err)
    1928          13 :     err = add_arg (gpg, "--");
    1929          13 :   if (!err && type == 0)
    1930             :     {
    1931          13 :       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
    1932          13 :       if (!s)
    1933           0 :         err = gpg_error (GPG_ERR_INV_VALUE);
    1934             :       else
    1935          13 :         err = add_arg (gpg, s);
    1936             :     }
    1937          13 :   if (!err)
    1938          13 :     err = start (gpg);
    1939             : 
    1940          13 :   return err;
    1941             : }
    1942             : 
    1943             : 
    1944             : /* Add a single argument from a key to an -r option.  */
    1945             : static gpg_error_t
    1946          95 : add_arg_recipient (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
    1947             :                    gpgme_key_t key)
    1948             : {
    1949             :   gpg_error_t err;
    1950             : 
    1951          95 :   if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
    1952             :     {
    1953             :       /* We have no way to figure out which mail address was
    1954             :        * requested.  FIXME: It would be possible to figure this out by
    1955             :        * consulting the SENDER property of the context.  */
    1956           0 :       err = gpg_error (GPG_ERR_INV_USER_ID);
    1957             :     }
    1958             :   else
    1959          95 :     err = add_arg (gpg, key->subkeys->fpr);
    1960             : 
    1961          95 :   return err;
    1962             : }
    1963             : 
    1964             : 
    1965             : /* Add a single argument from a USERID string to an -r option.  */
    1966             : static gpg_error_t
    1967           4 : add_arg_recipient_string (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
    1968             :                           const char *userid, int useridlen)
    1969             : {
    1970             :   gpg_error_t err;
    1971             : 
    1972           4 :   if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
    1973             :     {
    1974             :       char *tmpstr, *mbox;
    1975             : 
    1976           0 :       tmpstr = malloc (useridlen + 1);
    1977           0 :       if (!tmpstr)
    1978           0 :         err = gpg_error_from_syserror ();
    1979             :       else
    1980             :         {
    1981           0 :           memcpy (tmpstr, userid, useridlen);
    1982           0 :           tmpstr[useridlen] = 0;
    1983             : 
    1984           0 :           mbox = _gpgme_mailbox_from_userid (tmpstr);
    1985           0 :           if (!mbox)
    1986             :             {
    1987           0 :               err = gpg_error_from_syserror ();
    1988           0 :               if (gpg_err_code (err) == GPG_ERR_EINVAL)
    1989           0 :                 err = gpg_error (GPG_ERR_INV_USER_ID);
    1990             :             }
    1991             :           else
    1992           0 :             err = add_arg (gpg, mbox);
    1993             : 
    1994           0 :           free (mbox);
    1995           0 :           free (tmpstr);
    1996             :         }
    1997             :     }
    1998             :   else
    1999           4 :     err = add_arg_len (gpg, NULL, userid, useridlen);
    2000             : 
    2001           4 :   return err;
    2002             : }
    2003             : 
    2004             : 
    2005             : static gpgme_error_t
    2006          57 : append_args_from_recipients (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
    2007             :                              gpgme_key_t recp[])
    2008             : {
    2009          57 :   gpgme_error_t err = 0;
    2010          57 :   int i = 0;
    2011             : 
    2012         209 :   while (recp[i])
    2013             :     {
    2014          95 :       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
    2015           0 :         err = gpg_error (GPG_ERR_INV_VALUE);
    2016          95 :       if (!err)
    2017          95 :         err = add_arg (gpg, "-r");
    2018          95 :       if (!err)
    2019          95 :         err = add_arg_recipient (gpg, flags, recp[i]);
    2020          95 :       if (err)
    2021           0 :         break;
    2022          95 :       i++;
    2023             :     }
    2024          57 :   return err;
    2025             : }
    2026             : 
    2027             : 
    2028             : /* Take recipients from the LF delimited STRING and add -r args.  */
    2029             : static gpg_error_t
    2030           2 : append_args_from_recipients_string (engine_gpg_t gpg,
    2031             :                                     gpgme_encrypt_flags_t flags,
    2032             :                                     const char *string)
    2033             : {
    2034           2 :   gpg_error_t err = 0;
    2035           2 :   gpgme_encrypt_flags_t orig_flags = flags;
    2036           2 :   int any = 0;
    2037           2 :   int ignore = 0;
    2038           2 :   int hidden = 0;
    2039           2 :   int file = 0;
    2040             :   const char *s;
    2041             :   int n;
    2042             : 
    2043             :   do
    2044             :     {
    2045             :       /* Skip leading white space */
    2046          12 :       while (*string == ' ' || *string == '\t')
    2047           0 :         string++;
    2048           6 :       if (!*string)
    2049           2 :         break;
    2050             : 
    2051             :       /* Look for the LF. */
    2052           4 :       s = strchr (string, '\n');
    2053           4 :       if (s)
    2054           2 :         n = s - string;
    2055             :       else
    2056           2 :         n = strlen (string);
    2057           8 :       while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
    2058           0 :         n--;
    2059             : 
    2060           4 :       if (!ignore && n == 2 && !memcmp (string, "--", 2))
    2061           0 :         ignore = 1;
    2062           4 :       else if (!ignore && n == 8 && !memcmp (string, "--hidden", 8))
    2063           0 :         hidden = 1;
    2064           4 :       else if (!ignore && n == 11 && !memcmp (string, "--no-hidden", 11))
    2065           0 :         hidden = 0;
    2066           4 :       else if (!ignore && n == 6 && !memcmp (string, "--file", 6))
    2067             :         {
    2068           0 :           file = 1;
    2069             :           /* Because the key is used as is we need to ignore this flag:  */
    2070           0 :           flags &= ~GPGME_ENCRYPT_WANT_ADDRESS;
    2071             :         }
    2072           4 :       else if (!ignore && n == 9 && !memcmp (string, "--no-file", 9))
    2073             :         {
    2074           0 :           file = 0;
    2075           0 :           flags = orig_flags;
    2076             :         }
    2077           4 :       else if (n) /* Not empty - use it.  */
    2078             :         {
    2079           4 :           err = add_arg (gpg, file? (hidden? "-F":"-f") : (hidden? "-R":"-r"));
    2080           4 :           if (!err)
    2081           4 :             err = add_arg_recipient_string (gpg, flags, string, n);
    2082           4 :           if (!err)
    2083           4 :             any = 1;
    2084             :         }
    2085             : 
    2086           4 :       string += n + !!s;
    2087             :     }
    2088           4 :   while (!err);
    2089             : 
    2090           2 :   if (!err && !any)
    2091           0 :     err = gpg_error (GPG_ERR_MISSING_KEY);
    2092           2 :   return err;
    2093             : }
    2094             : 
    2095             : 
    2096             : static gpgme_error_t
    2097          64 : gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
    2098             :              gpgme_encrypt_flags_t flags,
    2099             :              gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
    2100             : {
    2101          64 :   engine_gpg_t gpg = engine;
    2102          64 :   gpgme_error_t err = 0;
    2103             : 
    2104          64 :   if (recp || recpstring)
    2105          44 :     err = add_arg (gpg, "--encrypt");
    2106             : 
    2107          64 :   if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
    2108          21 :     err = add_arg (gpg, "--symmetric");
    2109             : 
    2110          64 :   if (!err && use_armor)
    2111          45 :     err = add_arg (gpg, "--armor");
    2112             : 
    2113          64 :   if (!err && (flags & GPGME_ENCRYPT_WRAP))
    2114             :     {
    2115             :       /* gpg is current not able to detect already compressed
    2116             :        * packets.  Thus when using
    2117             :        *   gpg --unwrap -d | gpg --no-literal -e
    2118             :        * the encryption would add an additional compression layer.
    2119             :        * We better suppress that.  */
    2120           0 :       flags |= GPGME_ENCRYPT_NO_COMPRESS;
    2121           0 :       err = add_arg (gpg, "--no-literal");
    2122             :     }
    2123             : 
    2124          64 :   if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
    2125           0 :     err = add_arg (gpg, "--compress-algo=none");
    2126             : 
    2127          64 :   if (!err && (flags & GPGME_ENCRYPT_THROW_KEYIDS))
    2128           0 :     err = add_arg (gpg, "--throw-keyids");
    2129             : 
    2130          64 :   if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
    2131           0 :       && have_gpg_version (gpg, "2.1.14"))
    2132           0 :     err = add_arg (gpg, "--mimemode");
    2133             : 
    2134          64 :   if (recp || recpstring)
    2135             :     {
    2136             :       /* If we know that all recipients are valid (full or ultimate trust)
    2137             :          we can suppress further checks.  */
    2138          44 :       if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
    2139          44 :         err = add_arg (gpg, "--always-trust");
    2140             : 
    2141          44 :       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
    2142           6 :         err = add_arg (gpg, "--no-encrypt-to");
    2143             : 
    2144          44 :       if (!err && !recp && recpstring)
    2145           1 :         err = append_args_from_recipients_string (gpg, flags, recpstring);
    2146          43 :       else if (!err)
    2147          43 :         err = append_args_from_recipients (gpg, flags, recp);
    2148             :     }
    2149             : 
    2150             :   /* Tell the gpg object about the data.  */
    2151          64 :   if (!err)
    2152          64 :     err = add_arg (gpg, "--output");
    2153          64 :   if (!err)
    2154          64 :     err = add_arg (gpg, "-");
    2155          64 :   if (!err)
    2156          64 :     err = add_data (gpg, ciph, 1, 1);
    2157          64 :   if (gpgme_data_get_file_name (plain))
    2158             :     {
    2159           4 :       if (!err)
    2160           4 :         err = add_arg (gpg, "--set-filename");
    2161           4 :       if (!err)
    2162           4 :         err = add_arg (gpg, gpgme_data_get_file_name (plain));
    2163             :     }
    2164          64 :   if (!err)
    2165          64 :     err = add_input_size_hint (gpg, plain);
    2166          64 :   if (!err)
    2167          64 :     err = add_arg (gpg, "--");
    2168          64 :   if (!err)
    2169          64 :     err = add_data (gpg, plain, -1, 0);
    2170             : 
    2171          64 :   if (!err)
    2172          64 :     err = start (gpg);
    2173             : 
    2174          64 :   return err;
    2175             : }
    2176             : 
    2177             : 
    2178             : static gpgme_error_t
    2179          18 : gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
    2180             :                   const char *recpstring,
    2181             :                   gpgme_encrypt_flags_t flags, gpgme_data_t plain,
    2182             :                   gpgme_data_t ciph, int use_armor,
    2183             :                   gpgme_ctx_t ctx /* FIXME */)
    2184             : {
    2185          18 :   engine_gpg_t gpg = engine;
    2186          18 :   gpgme_error_t err = 0;
    2187             : 
    2188          18 :   if (recp || recpstring)
    2189          15 :     err = add_arg (gpg, "--encrypt");
    2190             : 
    2191          18 :   if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
    2192           3 :     err = add_arg (gpg, "--symmetric");
    2193             : 
    2194          18 :   if (!err)
    2195          18 :     err = add_arg (gpg, "--sign");
    2196          18 :   if (!err && use_armor)
    2197          14 :     err = add_arg (gpg, "--armor");
    2198             : 
    2199          18 :   if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
    2200           0 :     err = add_arg (gpg, "--compress-algo=none");
    2201             : 
    2202          18 :   if (!err && (flags & GPGME_ENCRYPT_THROW_KEYIDS))
    2203           0 :     err = add_arg (gpg, "--throw-keyids");
    2204             : 
    2205          18 :   if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
    2206           0 :       && have_gpg_version (gpg, "2.1.14"))
    2207           0 :     err = add_arg (gpg, "--mimemode");
    2208             : 
    2209          18 :   if (recp || recpstring)
    2210             :     {
    2211             :       /* If we know that all recipients are valid (full or ultimate trust)
    2212             :          we can suppress further checks.  */
    2213          15 :       if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
    2214          11 :         err = add_arg (gpg, "--always-trust");
    2215             : 
    2216          15 :       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
    2217          10 :         err = add_arg (gpg, "--no-encrypt-to");
    2218             : 
    2219          15 :       if (!err && !recp && recpstring)
    2220           1 :         err = append_args_from_recipients_string (gpg, flags, recpstring);
    2221          14 :       else if (!err)
    2222          14 :         err = append_args_from_recipients (gpg, flags, recp);
    2223             :     }
    2224             : 
    2225          18 :   if (!err)
    2226          18 :     err = append_args_from_signers (gpg, ctx);
    2227             : 
    2228          18 :   if (!err)
    2229          18 :     err = append_args_from_sender (gpg, ctx);
    2230             : 
    2231          18 :   if (!err)
    2232          18 :     err = append_args_from_sig_notations (gpg, ctx);
    2233             : 
    2234             :   /* Tell the gpg object about the data.  */
    2235          18 :   if (!err)
    2236          18 :     err = add_arg (gpg, "--output");
    2237          18 :   if (!err)
    2238          18 :     err = add_arg (gpg, "-");
    2239          18 :   if (!err)
    2240          18 :     err = add_data (gpg, ciph, 1, 1);
    2241          18 :   if (gpgme_data_get_file_name (plain))
    2242             :     {
    2243           0 :       if (!err)
    2244           0 :         err = add_arg (gpg, "--set-filename");
    2245           0 :       if (!err)
    2246           0 :         err = add_arg (gpg, gpgme_data_get_file_name (plain));
    2247             :     }
    2248          18 :   if (!err)
    2249          18 :     err = add_input_size_hint (gpg, plain);
    2250          18 :   if (!err)
    2251          18 :     err = add_arg (gpg, "--");
    2252          18 :   if (!err)
    2253          18 :     err = add_data (gpg, plain, -1, 0);
    2254             : 
    2255          18 :   if (!err)
    2256          18 :     err = start (gpg);
    2257             : 
    2258          18 :   return err;
    2259             : }
    2260             : 
    2261             : 
    2262             : static gpgme_error_t
    2263          10 : export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
    2264             :                gpgme_data_t keydata, int use_armor)
    2265             : {
    2266          10 :   gpgme_error_t err = 0;
    2267             : 
    2268          10 :   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
    2269             :                 |GPGME_EXPORT_MODE_MINIMAL
    2270             :                 |GPGME_EXPORT_MODE_SECRET)))
    2271           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
    2272             : 
    2273          10 :   if ((mode & GPGME_EXPORT_MODE_MINIMAL))
    2274             :     {
    2275           0 :       if ((mode & GPGME_EXPORT_MODE_NOUID))
    2276           0 :         err = add_arg (gpg, "--export-options=export-minimal,export-drop-uids");
    2277             :       else
    2278           0 :         err = add_arg (gpg, "--export-options=export-minimal");
    2279             :     }
    2280          10 :   else if ((mode & GPGME_EXPORT_MODE_NOUID))
    2281           0 :     err = add_arg (gpg, "--export-options=export-drop-uids");
    2282             : 
    2283          10 :   if (err)
    2284             :     ;
    2285          10 :   else if ((mode & GPGME_EXPORT_MODE_EXTERN))
    2286             :     {
    2287           0 :       err = add_arg (gpg, "--send-keys");
    2288           0 :       if (!err && (mode & GPGME_EXPORT_MODE_NOUID))
    2289           0 :         err = add_arg (gpg, "--keyserver-options=export-drop-uids");
    2290             :     }
    2291             :   else
    2292             :     {
    2293          10 :       if ((mode & GPGME_EXPORT_MODE_SECRET))
    2294           0 :         err = add_arg (gpg, "--export-secret-keys");
    2295             :       else
    2296          10 :         err = add_arg (gpg, "--export");
    2297          10 :       if (!err && use_armor)
    2298           8 :         err = add_arg (gpg, "--armor");
    2299          10 :       if (!err)
    2300          10 :         err = add_data (gpg, keydata, 1, 1);
    2301             :     }
    2302          10 :   if (!err)
    2303          10 :     err = add_arg (gpg, "--");
    2304             : 
    2305          10 :   return err;
    2306             : }
    2307             : 
    2308             : 
    2309             : static gpgme_error_t
    2310           0 : gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
    2311             :             gpgme_data_t keydata, int use_armor)
    2312             : {
    2313           0 :   engine_gpg_t gpg = engine;
    2314             :   gpgme_error_t err;
    2315             : 
    2316           0 :   err = export_common (gpg, mode, keydata, use_armor);
    2317             : 
    2318           0 :   if (!err && pattern && *pattern)
    2319           0 :     err = add_arg (gpg, pattern);
    2320             : 
    2321           0 :   if (!err)
    2322           0 :     err = start (gpg);
    2323             : 
    2324           0 :   return err;
    2325             : }
    2326             : 
    2327             : 
    2328             : static gpgme_error_t
    2329          10 : gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
    2330             :                 gpgme_data_t keydata, int use_armor)
    2331             : {
    2332          10 :   engine_gpg_t gpg = engine;
    2333             :   gpgme_error_t err;
    2334             : 
    2335          10 :   err = export_common (gpg, mode, keydata, use_armor);
    2336             : 
    2337          10 :   if (pattern)
    2338             :     {
    2339          86 :       while (!err && *pattern && **pattern)
    2340          66 :         err = add_arg (gpg, *(pattern++));
    2341             :     }
    2342             : 
    2343          10 :   if (!err)
    2344          10 :     err = start (gpg);
    2345             : 
    2346          10 :   return err;
    2347             : }
    2348             : 
    2349             : 
    2350             : 
    2351             : /* Helper to add algo, usage, and expire to the list of args.  */
    2352             : static gpgme_error_t
    2353          75 : gpg_add_algo_usage_expire (engine_gpg_t gpg,
    2354             :                            const char *algo,
    2355             :                            unsigned long expires,
    2356             :                            unsigned int flags)
    2357             : {
    2358             :   gpg_error_t err;
    2359             : 
    2360             :   /* This condition is only required to allow the use of gpg < 2.1.16 */
    2361          75 :   if (algo
    2362          46 :       || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
    2363             :                    | GPGME_CREATE_CERT | GPGME_CREATE_AUTH
    2364             :                    | GPGME_CREATE_NOEXPIRE))
    2365          14 :       || expires)
    2366             :     {
    2367          65 :       err = add_arg (gpg, algo? algo : "default");
    2368          65 :       if (!err)
    2369             :         {
    2370             :           char tmpbuf[5*4+1];
    2371         260 :           snprintf (tmpbuf, sizeof tmpbuf, "%s%s%s%s",
    2372          65 :                     (flags & GPGME_CREATE_SIGN)? " sign":"",
    2373          65 :                     (flags & GPGME_CREATE_ENCR)? " encr":"",
    2374          65 :                     (flags & GPGME_CREATE_CERT)? " cert":"",
    2375          65 :                     (flags & GPGME_CREATE_AUTH)? " auth":"");
    2376          65 :           err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
    2377             :         }
    2378         130 :       if (!err)
    2379             :         {
    2380          65 :           if ((flags & GPGME_CREATE_NOEXPIRE))
    2381           4 :             err = add_arg (gpg, "never");
    2382          61 :           else if (expires == 0)
    2383          57 :             err = add_arg (gpg, "-");
    2384             :           else
    2385             :             {
    2386             :               char tmpbuf[8+20];
    2387           4 :               snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
    2388           4 :               err = add_arg (gpg, tmpbuf);
    2389             :             }
    2390             :         }
    2391             :     }
    2392             :   else
    2393          10 :     err = 0;
    2394             : 
    2395          75 :   return err;
    2396             : }
    2397             : 
    2398             : 
    2399             : static gpgme_error_t
    2400           6 : gpg_createkey_from_param (engine_gpg_t gpg,
    2401             :                           gpgme_data_t help_data, unsigned int extraflags)
    2402             : {
    2403             :   gpgme_error_t err;
    2404             : 
    2405           6 :   err = add_arg (gpg, "--gen-key");
    2406           6 :   if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
    2407           0 :     err = add_arg (gpg, "--armor");
    2408           6 :   if (!err)
    2409           6 :     err = add_arg (gpg, "--");
    2410           6 :   if (!err)
    2411           6 :     err = add_data (gpg, help_data, -1, 0);
    2412           6 :   if (!err)
    2413           6 :     err = start (gpg);
    2414           6 :   return err;
    2415             : }
    2416             : 
    2417             : 
    2418             : static gpgme_error_t
    2419          49 : gpg_createkey (engine_gpg_t gpg,
    2420             :                const char *userid, const char *algo,
    2421             :                unsigned long expires,
    2422             :                unsigned int flags,
    2423             :                unsigned int extraflags)
    2424             : {
    2425             :   gpgme_error_t err;
    2426             : 
    2427          49 :   err = add_arg (gpg, "--quick-gen-key");
    2428          49 :   if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
    2429           0 :     err = add_arg (gpg, "--armor");
    2430          49 :   if (!err && (flags & GPGME_CREATE_NOPASSWD))
    2431             :     {
    2432          46 :       err = add_arg (gpg, "--passphrase");
    2433          46 :       if (!err)
    2434          46 :         err = add_arg (gpg, "");
    2435          46 :       if (!err)
    2436          46 :         err = add_arg (gpg, "--batch");
    2437             :     }
    2438          49 :   if (!err && (flags & GPGME_CREATE_FORCE))
    2439           3 :     err = add_arg (gpg, "--yes");
    2440          49 :   if (!err)
    2441          49 :     err = add_arg (gpg, "--");
    2442          49 :   if (!err)
    2443          49 :     err = add_arg (gpg, userid);
    2444             : 
    2445          49 :   if (!err)
    2446          49 :     err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
    2447             : 
    2448          49 :   if (!err)
    2449          49 :     err = start (gpg);
    2450          49 :   return err;
    2451             : }
    2452             : 
    2453             : 
    2454             : static gpgme_error_t
    2455          26 : gpg_addkey (engine_gpg_t gpg,
    2456             :             const char *algo,
    2457             :             unsigned long expires,
    2458             :             gpgme_key_t key,
    2459             :             unsigned int flags,
    2460             :             unsigned int extraflags)
    2461             : {
    2462             :   gpgme_error_t err;
    2463             : 
    2464          26 :   if (!key || !key->fpr)
    2465           0 :     return gpg_error (GPG_ERR_INV_ARG);
    2466             : 
    2467          26 :   err = add_arg (gpg, "--quick-addkey");
    2468          26 :   if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
    2469           0 :     err = add_arg (gpg, "--armor");
    2470          26 :   if (!err && (flags & GPGME_CREATE_NOPASSWD))
    2471             :     {
    2472          24 :       err = add_arg (gpg, "--passphrase");
    2473          24 :       if (!err)
    2474          24 :         err = add_arg (gpg, "");
    2475          24 :       if (!err)
    2476          24 :         err = add_arg (gpg, "--batch");
    2477             :     }
    2478          26 :   if (!err)
    2479          26 :     err = add_arg (gpg, "--");
    2480          26 :   if (!err)
    2481          26 :     err = add_arg (gpg, key->fpr);
    2482             : 
    2483          26 :   if (!err)
    2484          26 :     err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
    2485             : 
    2486          26 :   if (!err)
    2487          26 :     err = start (gpg);
    2488          26 :   return err;
    2489             : }
    2490             : 
    2491             : 
    2492             : static gpgme_error_t
    2493          28 : gpg_adduid (engine_gpg_t gpg,
    2494             :             gpgme_key_t key,
    2495             :             const char *userid,
    2496             :             unsigned int extraflags)
    2497             : {
    2498             :   gpgme_error_t err;
    2499             : 
    2500          28 :   if (!key || !key->fpr || !userid)
    2501           0 :     return gpg_error (GPG_ERR_INV_ARG);
    2502             : 
    2503          28 :   if ((extraflags & GENKEY_EXTRAFLAG_SETPRIMARY))
    2504             :     {
    2505           0 :       if (!have_gpg_version (gpg, "2.1.20"))
    2506           0 :         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
    2507             :       else
    2508           0 :         err = add_arg (gpg, "--quick-set-primary-uid");
    2509             :     }
    2510          28 :   else if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
    2511           7 :     err = add_arg (gpg, "--quick-revuid");
    2512             :   else
    2513          21 :     err = add_arg (gpg, "--quick-adduid");
    2514             : 
    2515          28 :   if (!err)
    2516          28 :     err = add_arg (gpg, "--");
    2517          28 :   if (!err)
    2518          28 :     err = add_arg (gpg, key->fpr);
    2519          28 :   if (!err)
    2520          28 :     err = add_arg (gpg, userid);
    2521             : 
    2522          28 :   if (!err)
    2523          28 :     err = start (gpg);
    2524          28 :   return err;
    2525             : }
    2526             : 
    2527             : 
    2528             : static gpgme_error_t
    2529         109 : gpg_genkey (void *engine,
    2530             :             const char *userid, const char *algo,
    2531             :             unsigned long reserved, unsigned long expires,
    2532             :             gpgme_key_t key, unsigned int flags,
    2533             :             gpgme_data_t help_data, unsigned int extraflags,
    2534             :             gpgme_data_t pubkey, gpgme_data_t seckey)
    2535             : {
    2536         109 :   engine_gpg_t gpg = engine;
    2537             :   gpgme_error_t err;
    2538             : 
    2539             :   (void)reserved;
    2540             : 
    2541         109 :   if (!gpg)
    2542           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    2543             : 
    2544             :   /* If HELP_DATA is given the use of the old interface
    2545             :    * (gpgme_op_genkey) has been requested.  The other modes are:
    2546             :    *
    2547             :    *  USERID && !KEY          - Create a new keyblock.
    2548             :    * !USERID &&  KEY          - Add a new subkey to KEY (gpg >= 2.1.14)
    2549             :    *  USERID &&  KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14).
    2550             :    *                            or set a flag on a user id.
    2551             :    */
    2552         109 :   if (help_data)
    2553             :     {
    2554             :       /* We need a special mechanism to get the fd of a pipe here, so
    2555             :          that we can use this for the %pubring and %secring
    2556             :          parameters.  We don't have this yet, so we implement only the
    2557             :          adding to the standard keyrings.  */
    2558           6 :       if (pubkey || seckey)
    2559           0 :         err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
    2560             :       else
    2561           6 :         err = gpg_createkey_from_param (gpg, help_data, extraflags);
    2562             :     }
    2563         103 :   else if (!have_gpg_version (gpg, "2.1.13"))
    2564           0 :     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
    2565         103 :   else if (userid && !key)
    2566          49 :     err = gpg_createkey (gpg, userid, algo, expires, flags, extraflags);
    2567          54 :   else if (!userid && key)
    2568          26 :     err = gpg_addkey (gpg, algo, expires, key, flags, extraflags);
    2569          28 :   else if (userid && key && !algo)
    2570          28 :     err = gpg_adduid (gpg, key, userid, extraflags);
    2571             :   else
    2572           0 :     err = gpg_error (GPG_ERR_INV_VALUE);
    2573             : 
    2574         109 :   return err;
    2575             : }
    2576             : 
    2577             : /* Return the next DELIM delimited string from DATA as a C-string.
    2578             :    The caller needs to provide the address of a pointer variable which
    2579             :    he has to set to NULL before the first call.  After the last call
    2580             :    to this function, this function needs to be called once more with
    2581             :    DATA set to NULL so that the function can release its internal
    2582             :    state.  After that the pointer variable is free for use again.
    2583             :    Note that we use a delimiter and thus a trailing delimiter is not
    2584             :    required.  DELIM may not be changed after the first call. */
    2585             : static const char *
    2586           0 : string_from_data (gpgme_data_t data, int delim,
    2587             :                   void **helpptr, gpgme_error_t *r_err)
    2588             : {
    2589             : #define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that.  */
    2590             :   struct {
    2591             :     int  eof_seen;
    2592             :     int  nbytes;      /* Length of the last returned string including
    2593             :                          the delimiter. */
    2594             :     int  buflen;      /* Valid length of BUF.  */
    2595             :     char buf[MYBUFLEN+1];  /* Buffer with one byte extra space.  */
    2596             :   } *self;
    2597             :   char *p;
    2598             :   int nread;
    2599             : 
    2600           0 :   *r_err = 0;
    2601           0 :   if (!data)
    2602             :     {
    2603           0 :       if (*helpptr)
    2604             :         {
    2605           0 :           free (*helpptr);
    2606           0 :           *helpptr = NULL;
    2607             :         }
    2608           0 :       return NULL;
    2609             :     }
    2610             : 
    2611           0 :   if (*helpptr)
    2612           0 :     self = *helpptr;
    2613             :   else
    2614             :     {
    2615           0 :       self = malloc (sizeof *self);
    2616           0 :       if (!self)
    2617             :         {
    2618           0 :           *r_err = gpg_error_from_syserror ();
    2619           0 :           return NULL;
    2620             :         }
    2621           0 :       *helpptr = self;
    2622           0 :       self->eof_seen = 0;
    2623           0 :       self->nbytes = 0;
    2624           0 :       self->buflen = 0;
    2625             :     }
    2626             : 
    2627           0 :   if (self->eof_seen)
    2628           0 :     return NULL;
    2629             : 
    2630           0 :   assert (self->nbytes <= self->buflen);
    2631           0 :   memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
    2632           0 :   self->buflen -= self->nbytes;
    2633           0 :   self->nbytes = 0;
    2634             : 
    2635             :   do
    2636             :     {
    2637             :       /* Fixme: This is fairly infective scanning because we may scan
    2638             :          the buffer several times.  */
    2639           0 :       p = memchr (self->buf, delim, self->buflen);
    2640           0 :       if (p)
    2641             :         {
    2642           0 :           *p = 0;
    2643           0 :           self->nbytes = p - self->buf + 1;
    2644           0 :           return self->buf;
    2645             :         }
    2646             : 
    2647           0 :       if ( !(MYBUFLEN - self->buflen) )
    2648             :         {
    2649             :           /* Not enough space - URL too long.  */
    2650           0 :           *r_err = gpg_error (GPG_ERR_TOO_LARGE);
    2651           0 :           return NULL;
    2652             :         }
    2653             : 
    2654           0 :       nread = gpgme_data_read (data, self->buf + self->buflen,
    2655           0 :                                MYBUFLEN - self->buflen);
    2656           0 :       if (nread < 0)
    2657             :         {
    2658           0 :           *r_err = gpg_error_from_syserror ();
    2659           0 :           return NULL;
    2660             :         }
    2661           0 :       self->buflen += nread;
    2662             :     }
    2663           0 :   while (nread);
    2664             : 
    2665             :   /* EOF reached.  If we have anything in the buffer, append a Nul and
    2666             :      return it. */
    2667           0 :   self->eof_seen = 1;
    2668           0 :   if (self->buflen)
    2669             :     {
    2670           0 :       self->buf[self->buflen] = 0;  /* (we allocated one extra byte)  */
    2671           0 :       return self->buf;
    2672             :     }
    2673           0 :   return NULL;
    2674             : #undef MYBUFLEN
    2675             : }
    2676             : 
    2677             : 
    2678             : 
    2679             : static gpgme_error_t
    2680          15 : gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
    2681             : {
    2682          15 :   engine_gpg_t gpg = engine;
    2683             :   gpgme_error_t err;
    2684             :   int idx;
    2685             :   gpgme_data_encoding_t dataenc;
    2686             : 
    2687          15 :   if (keydata && keyarray)
    2688           0 :     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
    2689             : 
    2690          15 :   dataenc = gpgme_data_get_encoding (keydata);
    2691             : 
    2692          15 :   if (keyarray)
    2693             :     {
    2694           0 :       err = add_arg (gpg, "--recv-keys");
    2695           0 :       if (!err)
    2696           0 :         err = add_arg (gpg, "--");
    2697           0 :       for (idx=0; !err && keyarray[idx]; idx++)
    2698             :         {
    2699           0 :           if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
    2700             :             ;
    2701           0 :           else if (!keyarray[idx]->subkeys)
    2702             :             ;
    2703           0 :           else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
    2704           0 :             err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
    2705           0 :           else if (*keyarray[idx]->subkeys->keyid)
    2706           0 :             err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
    2707             :         }
    2708             :     }
    2709          15 :   else if (dataenc == GPGME_DATA_ENCODING_URL
    2710          15 :            || dataenc == GPGME_DATA_ENCODING_URL0)
    2711           0 :     {
    2712             :       void *helpptr;
    2713             :       const char *string;
    2714             :       gpgme_error_t xerr;
    2715           0 :       int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
    2716             : 
    2717             :       /* FIXME: --fetch-keys is probably not correct because it can't
    2718             :          grok all kinds of URLs.  On Unix it should just work but on
    2719             :          Windows we will build the command line and that may fail for
    2720             :          some embedded control characters.  It is anyway limited to
    2721             :          the maximum size of the command line.  We need another
    2722             :          command which can take its input from a file.  Maybe we
    2723             :          should use an option to gpg to modify such commands (ala
    2724             :          --multifile).  */
    2725           0 :       err = add_arg (gpg, "--fetch-keys");
    2726           0 :       if (!err)
    2727           0 :         err = add_arg (gpg, "--");
    2728           0 :       helpptr = NULL;
    2729           0 :       while (!err
    2730           0 :              && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
    2731           0 :         err = add_arg (gpg, string);
    2732           0 :       if (!err)
    2733           0 :         err = xerr;
    2734           0 :       string_from_data (NULL, delim, &helpptr, &xerr);
    2735             :     }
    2736          15 :   else if (dataenc == GPGME_DATA_ENCODING_URLESC)
    2737             :     {
    2738             :       /* Already escaped URLs are not yet supported.  */
    2739           0 :       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
    2740             :     }
    2741             :   else
    2742             :     {
    2743          15 :       err = add_arg (gpg, "--import");
    2744          15 :       if (!err)
    2745          15 :         err = add_arg (gpg, "--");
    2746          15 :       if (!err)
    2747          15 :         err = add_data (gpg, keydata, -1, 0);
    2748             :     }
    2749             : 
    2750          15 :   if (!err)
    2751          15 :     err = start (gpg);
    2752             : 
    2753          15 :   return err;
    2754             : }
    2755             : 
    2756             : 
    2757             : /* The output for external keylistings in GnuPG is different from all
    2758             :    the other key listings.  We catch this here with a special
    2759             :    preprocessor that reformats the colon handler lines.  */
    2760             : static gpgme_error_t
    2761           0 : gpg_keylist_preprocess (char *line, char **r_line)
    2762             : {
    2763             :   enum
    2764             :     {
    2765             :       RT_NONE, RT_INFO, RT_PUB, RT_UID
    2766             :     }
    2767           0 :   rectype = RT_NONE;
    2768             : #define NR_FIELDS 16
    2769             :   char *field[NR_FIELDS];
    2770           0 :   int fields = 0;
    2771             :   size_t n;
    2772             : 
    2773           0 :   *r_line = NULL;
    2774             : 
    2775           0 :   while (line && fields < NR_FIELDS)
    2776             :     {
    2777           0 :       field[fields++] = line;
    2778           0 :       line = strchr (line, ':');
    2779           0 :       if (line)
    2780           0 :         *(line++) = '\0';
    2781             :     }
    2782             : 
    2783           0 :   if (!strcmp (field[0], "info"))
    2784           0 :     rectype = RT_INFO;
    2785           0 :   else if (!strcmp (field[0], "pub"))
    2786           0 :     rectype = RT_PUB;
    2787           0 :   else if (!strcmp (field[0], "uid"))
    2788           0 :     rectype = RT_UID;
    2789             :   else
    2790           0 :     rectype = RT_NONE;
    2791             : 
    2792           0 :   switch (rectype)
    2793             :     {
    2794             :     case RT_INFO:
    2795             :       /* FIXME: Eventually, check the version number at least.  */
    2796           0 :       return 0;
    2797             : 
    2798             :     case RT_PUB:
    2799           0 :       if (fields < 7)
    2800           0 :         return 0;
    2801             : 
    2802             :       /* The format is:
    2803             : 
    2804             :          pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
    2805             : 
    2806             :          as defined in 5.2. Machine Readable Indexes of the OpenPGP
    2807             :          HTTP Keyserver Protocol (draft).  Modern versions of the SKS
    2808             :          keyserver return the fingerprint instead of the keyid.  We
    2809             :          detect this here and use the v4 fingerprint format to convert
    2810             :          it to a key id.
    2811             : 
    2812             :          We want:
    2813             :          pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
    2814             :       */
    2815             : 
    2816           0 :       n = strlen (field[1]);
    2817           0 :       if (n > 16)
    2818             :         {
    2819           0 :           if (gpgrt_asprintf (r_line,
    2820             :                         "pub:o%s:%s:%s:%s:%s:%s::::::::\n"
    2821             :                         "fpr:::::::::%s:",
    2822           0 :                         field[6], field[3], field[2], field[1] + n - 16,
    2823             :                         field[4], field[5], field[1]) < 0)
    2824           0 :             return gpg_error_from_syserror ();
    2825             :         }
    2826             :       else
    2827             :         {
    2828           0 :           if (gpgrt_asprintf (r_line,
    2829             :                         "pub:o%s:%s:%s:%s:%s:%s::::::::",
    2830             :                         field[6], field[3], field[2], field[1],
    2831             :                         field[4], field[5]) < 0)
    2832           0 :             return gpg_error_from_syserror ();
    2833             :         }
    2834             : 
    2835           0 :       return 0;
    2836             : 
    2837             :     case RT_UID:
    2838             :       /* The format is:
    2839             : 
    2840             :          uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
    2841             : 
    2842             :          as defined in 5.2. Machine Readable Indexes of the OpenPGP
    2843             :          HTTP Keyserver Protocol (draft).
    2844             : 
    2845             :          For an ldap keyserver the format is:
    2846             :          uid:<escaped uid string>
    2847             : 
    2848             :          We want:
    2849             :          uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
    2850             :       */
    2851             : 
    2852             :       {
    2853             :         /* The user ID is percent escaped, but we want c-coded.
    2854             :            Because we have to replace each '%HL' by '\xHL', we need at
    2855             :            most 4/3 th the number of bytes.  But because we also need
    2856             :            to escape the backslashes we allocate twice as much.  */
    2857           0 :         char *uid = malloc (2 * strlen (field[1]) + 1);
    2858             :         char *src;
    2859             :         char *dst;
    2860             : 
    2861           0 :         if (! uid)
    2862           0 :           return gpg_error_from_syserror ();
    2863           0 :         src = field[1];
    2864           0 :         dst = uid;
    2865           0 :         while (*src)
    2866             :           {
    2867           0 :             if (*src == '%')
    2868             :               {
    2869           0 :                 *(dst++) = '\\';
    2870           0 :                 *(dst++) = 'x';
    2871           0 :                 src++;
    2872             :                 /* Copy the next two bytes unconditionally.  */
    2873           0 :                 if (*src)
    2874           0 :                   *(dst++) = *(src++);
    2875           0 :                 if (*src)
    2876           0 :                   *(dst++) = *(src++);
    2877             :               }
    2878           0 :             else if (*src == '\\')
    2879             :               {
    2880           0 :                 *dst++ = '\\';
    2881           0 :                 *dst++ = '\\';
    2882           0 :                 src++;
    2883             :               }
    2884             :             else
    2885           0 :               *(dst++) = *(src++);
    2886             :           }
    2887           0 :         *dst = '\0';
    2888             : 
    2889           0 :         if (fields < 4)
    2890             :           {
    2891           0 :             if (gpgrt_asprintf (r_line, "uid:o::::::::%s:", uid) < 0)
    2892           0 :               return gpg_error_from_syserror ();
    2893             :           }
    2894             :         else
    2895             :           {
    2896           0 :             if (gpgrt_asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
    2897             :                                 field[4], field[2], field[3], uid) < 0)
    2898           0 :               return gpg_error_from_syserror ();
    2899             :           }
    2900             :       }
    2901           0 :       return 0;
    2902             : 
    2903             :     case RT_NONE:
    2904             :       /* Unknown record.  */
    2905           0 :       break;
    2906             :     }
    2907           0 :   return 0;
    2908             : 
    2909             : }
    2910             : 
    2911             : 
    2912             : static gpg_error_t
    2913         334 : gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
    2914             :                            gpgme_keylist_mode_t mode)
    2915             : {
    2916             :   gpg_error_t err;
    2917             : 
    2918         334 :   err = add_arg (gpg, "--with-colons");
    2919             : 
    2920             :   /* Since gpg 2.1.15 fingerprints are always printed, thus there is
    2921             :    * no more need to explicitly request them.  */
    2922         333 :   if (!have_gpg_version (gpg, "2.1.15"))
    2923             :     {
    2924           0 :       if (!err)
    2925           0 :         err = add_arg (gpg, "--fixed-list-mode");
    2926           0 :       if (!err)
    2927           0 :         err = add_arg (gpg, "--with-fingerprint");
    2928           0 :       if (!err)
    2929           0 :         err = add_arg (gpg, "--with-fingerprint");
    2930             :     }
    2931             : 
    2932         333 :   if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU)
    2933          28 :       && have_gpg_version (gpg, "2.1.16"))
    2934          28 :     err = add_arg (gpg, "--with-tofu-info");
    2935             : 
    2936         333 :   if (!err && (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
    2937           2 :     err = add_arg (gpg, "--with-secret");
    2938             : 
    2939         333 :   if (!err
    2940         333 :       && (mode & GPGME_KEYLIST_MODE_SIGS)
    2941          30 :       && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
    2942             :     {
    2943           8 :       err = add_arg (gpg, "--list-options");
    2944           8 :       if (!err)
    2945           8 :         err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
    2946             :     }
    2947             : 
    2948         333 :   if (!err)
    2949             :     {
    2950         333 :       if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
    2951             :         {
    2952           1 :           if (secret_only)
    2953           0 :             err = gpg_error (GPG_ERR_NOT_SUPPORTED);
    2954           1 :           else if ( (mode & GPGME_KEYLIST_MODE_LOCAL))
    2955             :             {
    2956             :               /* The local+extern mode is special.  It works only with
    2957             :                  gpg >= 2.0.10.  FIXME: We should check that we have
    2958             :                  such a version to that we can return a proper error
    2959             :                  code.  The problem is that we don't know the context
    2960             :                  here and thus can't access the cached version number
    2961             :                  for the engine info structure.  */
    2962           1 :               err = add_arg (gpg, "--locate-keys");
    2963           1 :               if ((mode & GPGME_KEYLIST_MODE_SIGS))
    2964           1 :                 err = add_arg (gpg, "--with-sig-check");
    2965             :             }
    2966             :           else
    2967             :             {
    2968           0 :               err = add_arg (gpg, "--search-keys");
    2969           0 :               gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
    2970             :             }
    2971             :         }
    2972             :       else
    2973             :         {
    2974         611 :           err = add_arg (gpg, secret_only ? "--list-secret-keys"
    2975         279 :                          : ((mode & GPGME_KEYLIST_MODE_SIGS)
    2976         279 :                             ? "--check-sigs" : "--list-keys"));
    2977             :         }
    2978             :     }
    2979             : 
    2980         333 :   if (!err)
    2981         333 :     err = add_arg (gpg, "--");
    2982             : 
    2983         333 :   return err;
    2984             : }
    2985             : 
    2986             : 
    2987             : static gpgme_error_t
    2988         328 : gpg_keylist (void *engine, const char *pattern, int secret_only,
    2989             :              gpgme_keylist_mode_t mode, int engine_flags)
    2990             : {
    2991         328 :   engine_gpg_t gpg = engine;
    2992             :   gpgme_error_t err;
    2993             : 
    2994             :   (void)engine_flags;
    2995             : 
    2996         328 :   err = gpg_keylist_build_options (gpg, secret_only, mode);
    2997             : 
    2998         327 :   if (!err && pattern && *pattern)
    2999         291 :     err = add_arg (gpg, pattern);
    3000             : 
    3001         327 :   if (!err)
    3002         327 :     err = start (gpg);
    3003             : 
    3004         317 :   return err;
    3005             : }
    3006             : 
    3007             : 
    3008             : static gpgme_error_t
    3009           6 : gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
    3010             :                  int reserved, gpgme_keylist_mode_t mode, int engine_flags)
    3011             : {
    3012           6 :   engine_gpg_t gpg = engine;
    3013             :   gpgme_error_t err;
    3014             : 
    3015             :   (void)engine_flags;
    3016             : 
    3017           6 :   if (reserved)
    3018           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    3019             : 
    3020           6 :   err = gpg_keylist_build_options (gpg, secret_only, mode);
    3021             : 
    3022           6 :   if (pattern)
    3023             :     {
    3024          20 :       while (!err && *pattern && **pattern)
    3025           8 :         err = add_arg (gpg, *(pattern++));
    3026             :     }
    3027             : 
    3028           6 :   if (!err)
    3029           6 :     err = start (gpg);
    3030             : 
    3031           6 :   return err;
    3032             : }
    3033             : 
    3034             : 
    3035             : static gpgme_error_t
    3036           5 : gpg_keylist_data (void *engine, gpgme_data_t data)
    3037             : {
    3038           5 :   engine_gpg_t gpg = engine;
    3039             :   gpgme_error_t err;
    3040             : 
    3041           5 :   if (!have_gpg_version (gpg, "2.1.14"))
    3042           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
    3043             : 
    3044           5 :   err = add_arg (gpg, "--with-colons");
    3045           5 :   if (!err)
    3046           5 :     err = add_arg (gpg, "--with-fingerprint");
    3047           5 :   if (!err)
    3048           5 :     err = add_arg (gpg, "--import-options");
    3049           5 :   if (!err)
    3050           5 :     err = add_arg (gpg, "import-show");
    3051           5 :   if (!err)
    3052           5 :     err = add_arg (gpg, "--dry-run");
    3053           5 :   if (!err)
    3054           5 :     err = add_arg (gpg, "--import");
    3055           5 :   if (!err)
    3056           5 :     err = add_arg (gpg, "--");
    3057           5 :   if (!err)
    3058           5 :     err = add_data (gpg, data, -1, 0);
    3059             : 
    3060           5 :   if (!err)
    3061           5 :     err = start (gpg);
    3062             : 
    3063           5 :   return err;
    3064             : }
    3065             : 
    3066             : 
    3067             : static gpgme_error_t
    3068           8 : gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
    3069             :              unsigned long expire, unsigned int flags,
    3070             :              gpgme_ctx_t ctx)
    3071             : {
    3072           8 :   engine_gpg_t gpg = engine;
    3073             :   gpgme_error_t err;
    3074             :   const char *s;
    3075             : 
    3076           8 :   if (!key || !key->fpr)
    3077           0 :     return gpg_error (GPG_ERR_INV_ARG);
    3078             : 
    3079           8 :   if (!have_gpg_version (gpg, "2.1.12"))
    3080           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
    3081             : 
    3082           8 :   if ((flags & GPGME_KEYSIGN_LOCAL))
    3083           6 :     err = add_arg (gpg, "--quick-lsign-key");
    3084             :   else
    3085           2 :     err = add_arg (gpg, "--quick-sign-key");
    3086             : 
    3087           8 :   if (!err)
    3088           8 :     err = append_args_from_signers (gpg, ctx);
    3089             : 
    3090             :   /* If an expiration time has been given use that.  If none has been
    3091             :    * given the default from gpg.conf is used.  To make sure not to set
    3092             :    * an expiration time at all the flag GPGME_KEYSIGN_NOEXPIRE can be
    3093             :    * used.  */
    3094           8 :   if (!err && (expire || (flags & GPGME_KEYSIGN_NOEXPIRE)))
    3095             :     {
    3096             :       char tmpbuf[8+20];
    3097             : 
    3098           8 :       if ((flags & GPGME_KEYSIGN_NOEXPIRE))
    3099           4 :         expire = 0;
    3100           8 :       snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expire);
    3101           8 :       err = add_arg (gpg, "--default-cert-expire");
    3102           8 :       if (!err)
    3103           8 :         err = add_arg (gpg, tmpbuf);
    3104             :     }
    3105             : 
    3106           8 :   if (!err)
    3107           8 :     err = add_arg (gpg, "--");
    3108             : 
    3109           8 :   if (!err)
    3110           8 :     err = add_arg (gpg, key->fpr);
    3111           8 :   if (!err && userid)
    3112             :     {
    3113           6 :       if ((flags & GPGME_KEYSIGN_LFSEP))
    3114             :         {
    3115           8 :           for (; !err && (s = strchr (userid, '\n')); userid = s + 1)
    3116           4 :             if ((s - userid))
    3117           4 :               err = add_arg_len (gpg, "=", userid, s - userid);
    3118           4 :           if (!err && *userid)
    3119           4 :             err = add_arg_pfx (gpg, "=", userid);
    3120             :         }
    3121             :       else
    3122           2 :         err = add_arg_pfx (gpg, "=", userid);
    3123             :     }
    3124             : 
    3125           8 :   if (!err)
    3126           8 :     err = start (gpg);
    3127             : 
    3128           8 :   return err;
    3129             : }
    3130             : 
    3131             : 
    3132             : static gpgme_error_t
    3133          12 : gpg_tofu_policy (void *engine, gpgme_key_t key, gpgme_tofu_policy_t policy)
    3134             : {
    3135          12 :   engine_gpg_t gpg = engine;
    3136             :   gpgme_error_t err;
    3137          12 :   const char *policystr = NULL;
    3138             : 
    3139          12 :   if (!key || !key->fpr)
    3140           0 :     return gpg_error (GPG_ERR_INV_ARG);
    3141             : 
    3142          12 :   switch (policy)
    3143             :     {
    3144           0 :     case GPGME_TOFU_POLICY_NONE:                           break;
    3145           2 :     case GPGME_TOFU_POLICY_AUTO:    policystr = "auto";    break;
    3146           3 :     case GPGME_TOFU_POLICY_GOOD:    policystr = "good";    break;
    3147           3 :     case GPGME_TOFU_POLICY_BAD:     policystr = "bad";     break;
    3148           2 :     case GPGME_TOFU_POLICY_ASK:     policystr = "ask";     break;
    3149           2 :     case GPGME_TOFU_POLICY_UNKNOWN: policystr = "unknown"; break;
    3150             :     }
    3151          12 :   if (!policystr)
    3152           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    3153             : 
    3154          12 :   if (!have_gpg_version (gpg, "2.1.10"))
    3155           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
    3156             : 
    3157          12 :   err = add_arg (gpg, "--tofu-policy");
    3158          12 :   if (!err)
    3159          12 :     err = add_arg (gpg, "--");
    3160          12 :   if (!err)
    3161          12 :     err = add_arg (gpg, policystr);
    3162          12 :   if (!err)
    3163          12 :     err = add_arg (gpg, key->fpr);
    3164             : 
    3165          12 :   if (!err)
    3166          12 :     err = start (gpg);
    3167             : 
    3168          12 :   return err;
    3169             : }
    3170             : 
    3171             : 
    3172             : static gpgme_error_t
    3173          47 : gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
    3174             :           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
    3175             :           int include_certs, gpgme_ctx_t ctx /* FIXME */)
    3176             : {
    3177          47 :   engine_gpg_t gpg = engine;
    3178             :   gpgme_error_t err;
    3179             : 
    3180             :   (void)include_certs;
    3181             : 
    3182          47 :   if (mode == GPGME_SIG_MODE_CLEAR)
    3183          10 :     err = add_arg (gpg, "--clearsign");
    3184             :   else
    3185             :     {
    3186          37 :       err = add_arg (gpg, "--sign");
    3187          37 :       if (!err && mode == GPGME_SIG_MODE_DETACH)
    3188          11 :         err = add_arg (gpg, "--detach");
    3189          37 :       if (!err && use_armor)
    3190          21 :         err = add_arg (gpg, "--armor");
    3191          37 :       if (!err)
    3192             :         {
    3193          37 :           if (gpgme_data_get_encoding (in) == GPGME_DATA_ENCODING_MIME
    3194           0 :               && have_gpg_version (gpg, "2.1.14"))
    3195           0 :             err = add_arg (gpg, "--mimemode");
    3196          37 :           else if (use_textmode)
    3197          20 :             err = add_arg (gpg, "--textmode");
    3198             :         }
    3199             :     }
    3200             : 
    3201          47 :   if (!err)
    3202          47 :     err = append_args_from_signers (gpg, ctx);
    3203          47 :   if (!err)
    3204          47 :     err = append_args_from_sender (gpg, ctx);
    3205          47 :   if (!err)
    3206          47 :     err = append_args_from_sig_notations (gpg, ctx);
    3207             : 
    3208          47 :   if (gpgme_data_get_file_name (in))
    3209             :     {
    3210           0 :       if (!err)
    3211           0 :         err = add_arg (gpg, "--set-filename");
    3212           0 :       if (!err)
    3213           0 :         err = add_arg (gpg, gpgme_data_get_file_name (in));
    3214             :     }
    3215             : 
    3216             :   /* Tell the gpg object about the data.  */
    3217          47 :   if (!err)
    3218          47 :     err = add_input_size_hint (gpg, in);
    3219          47 :   if (!err)
    3220          47 :     err = add_arg (gpg, "--");
    3221          47 :   if (!err)
    3222          47 :     err = add_data (gpg, in, -1, 0);
    3223          47 :   if (!err)
    3224          47 :     err = add_data (gpg, out, 1, 1);
    3225             : 
    3226          47 :   if (!err)
    3227          47 :     err = start (gpg);
    3228             : 
    3229          47 :   return err;
    3230             : }
    3231             : 
    3232             : static gpgme_error_t
    3233           5 : gpg_trustlist (void *engine, const char *pattern)
    3234             : {
    3235           5 :   engine_gpg_t gpg = engine;
    3236             :   gpgme_error_t err;
    3237             : 
    3238           5 :   err = add_arg (gpg, "--with-colons");
    3239           5 :   if (!err)
    3240           5 :     err = add_arg (gpg, "--list-trust-path");
    3241             : 
    3242             :   /* Tell the gpg object about the data.  */
    3243           5 :   if (!err)
    3244           5 :     err = add_arg (gpg, "--");
    3245           5 :   if (!err)
    3246           5 :     err = add_arg (gpg, pattern);
    3247             : 
    3248           5 :   if (!err)
    3249           5 :     err = start (gpg);
    3250             : 
    3251           5 :   return err;
    3252             : }
    3253             : 
    3254             : 
    3255             : static gpgme_error_t
    3256          57 : gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
    3257             :             gpgme_data_t plaintext, gpgme_ctx_t ctx)
    3258             : {
    3259          57 :   engine_gpg_t gpg = engine;
    3260             :   gpgme_error_t err;
    3261             : 
    3262          57 :   err = append_args_from_sender (gpg, ctx);
    3263          58 :   if (!err && ctx->auto_key_retrieve)
    3264           0 :     err = add_arg (gpg, "--auto-key-retrieve");
    3265             : 
    3266          58 :   if (err)
    3267             :     ;
    3268          58 :   else if (plaintext)
    3269             :     {
    3270             :       /* Normal or cleartext signature.  */
    3271          33 :       err = add_arg (gpg, "--output");
    3272          33 :       if (!err)
    3273          33 :         err = add_arg (gpg, "-");
    3274          33 :       if (!err)
    3275          33 :         err = add_input_size_hint (gpg, sig);
    3276          33 :       if (!err)
    3277          33 :         err = add_arg (gpg, "--");
    3278          33 :       if (!err)
    3279          33 :         err = add_data (gpg, sig, -1, 0);
    3280          33 :       if (!err)
    3281          33 :         err = add_data (gpg, plaintext, 1, 1);
    3282             :     }
    3283             :   else
    3284             :     {
    3285          25 :       err = add_arg (gpg, "--verify");
    3286          25 :       if (!err)
    3287          25 :         err = add_input_size_hint (gpg, signed_text);
    3288          25 :       if (!err)
    3289          25 :         err = add_arg (gpg, "--");
    3290          25 :       if (!err)
    3291          25 :         err = add_data (gpg, sig, -1, 0);
    3292          26 :       if (!err && signed_text)
    3293          26 :         err = add_data (gpg, signed_text, -1, 0);
    3294             :     }
    3295             : 
    3296          59 :   if (!err)
    3297          59 :     err = start (gpg);
    3298             : 
    3299          57 :   return err;
    3300             : }
    3301             : 
    3302             : 
    3303             : static void
    3304         754 : gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
    3305             : {
    3306         754 :   engine_gpg_t gpg = engine;
    3307             : 
    3308         754 :   gpg->io_cbs = *io_cbs;
    3309         754 : }
    3310             : 
    3311             : 
    3312             : static gpgme_error_t
    3313         750 : gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode)
    3314             : {
    3315         750 :   engine_gpg_t gpg = engine;
    3316             : 
    3317         750 :   gpg->pinentry_mode = mode;
    3318         750 :   return 0;
    3319             : }
    3320             : 
    3321             : 
    3322             : static gpgme_error_t
    3323          30 : gpg_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
    3324             : {
    3325          30 :   engine_gpg_t gpg = engine;
    3326             : #define MYBUFLEN 4096
    3327             :   char buf[MYBUFLEN];
    3328             :   int nread;
    3329          30 :   int any_written = 0;
    3330             : 
    3331          30 :   if (!(flags & GPGME_AUDITLOG_DIAG))
    3332             :     {
    3333           0 :       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
    3334             :     }
    3335             : 
    3336          30 :   if (!gpg || !output)
    3337             :     {
    3338           0 :       return gpg_error (GPG_ERR_INV_VALUE);
    3339             :     }
    3340             : 
    3341          30 :   if (!gpg->diagnostics)
    3342             :     {
    3343           0 :       return gpg_error (GPG_ERR_GENERAL);
    3344             :     }
    3345             : 
    3346          30 :   gpgme_data_rewind (gpg->diagnostics);
    3347             : 
    3348          30 :   while ((nread = gpgme_data_read (gpg->diagnostics, buf, MYBUFLEN)) > 0)
    3349             :     {
    3350          28 :       any_written = 1;
    3351          28 :       if (gpgme_data_write (output, buf, nread) == -1)
    3352           0 :         return gpg_error_from_syserror ();
    3353             :     }
    3354          30 :   if (!any_written)
    3355             :     {
    3356           2 :       return gpg_error (GPG_ERR_NO_DATA);
    3357             :     }
    3358             : 
    3359          28 :   if (nread == -1)
    3360           0 :     return gpg_error_from_syserror ();
    3361             : 
    3362          28 :   gpgme_data_rewind (output);
    3363          28 :   return 0;
    3364             : #undef MYBUFLEN
    3365             : }
    3366             : 
    3367             : 
    3368             : 
    3369             : struct engine_ops _gpgme_engine_ops_gpg =
    3370             :   {
    3371             :     /* Static functions.  */
    3372             :     _gpgme_get_default_gpg_name,
    3373             :     NULL,
    3374             :     gpg_get_version,
    3375             :     gpg_get_req_version,
    3376             :     gpg_new,
    3377             : 
    3378             :     /* Member functions.  */
    3379             :     gpg_release,
    3380             :     NULL,                               /* reset */
    3381             :     gpg_set_status_cb,
    3382             :     gpg_set_status_handler,
    3383             :     gpg_set_command_handler,
    3384             :     gpg_set_colon_line_handler,
    3385             :     gpg_set_locale,
    3386             :     NULL,                               /* set_protocol */
    3387             :     gpg_set_engine_flags,               /* set_engine_flags */
    3388             :     gpg_decrypt,
    3389             :     gpg_delete,
    3390             :     gpg_edit,
    3391             :     gpg_encrypt,
    3392             :     gpg_encrypt_sign,
    3393             :     gpg_export,
    3394             :     gpg_export_ext,
    3395             :     gpg_genkey,
    3396             :     gpg_import,
    3397             :     gpg_keylist,
    3398             :     gpg_keylist_ext,
    3399             :     gpg_keylist_data,
    3400             :     gpg_keysign,
    3401             :     gpg_tofu_policy,    /* tofu_policy */
    3402             :     gpg_sign,
    3403             :     gpg_trustlist,
    3404             :     gpg_verify,
    3405             :     gpg_getauditlog,
    3406             :     NULL,               /* opassuan_transact */
    3407             :     NULL,               /* conf_load */
    3408             :     NULL,               /* conf_save */
    3409             :     NULL,               /* conf_dir */
    3410             :     NULL,               /* query_swdb */
    3411             :     gpg_set_io_cbs,
    3412             :     gpg_io_event,
    3413             :     gpg_cancel,
    3414             :     NULL,               /* cancel_op */
    3415             :     gpg_passwd,
    3416             :     gpg_set_pinentry_mode,
    3417             :     NULL                /* opspawn */
    3418             :   };

Generated by: LCOV version 1.13