LCOV - code coverage report
Current view: top level - src - engine-gpg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 799 1188 67.3 %
Date: 2015-11-05 17:14:26 Functions: 43 50 86.0 %

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

Generated by: LCOV version 1.11