LCOV - code coverage report
Current view: top level - src - engine-gpg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1061 1456 72.9 %
Date: 2017-03-02 17:11:10 Functions: 57 63 90.5 %

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

Generated by: LCOV version 1.13