LCOV - code coverage report
Current view: top level - src - engine-gpg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 929 1446 64.2 %
Date: 2016-11-29 15:07:43 Functions: 50 63 79.4 %

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

Generated by: LCOV version 1.11