LCOV - code coverage report
Current view: top level - src - engine-gpg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 884 1252 70.6 %
Date: 2016-09-12 13:07:23 Functions: 47 53 88.7 %

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

Generated by: LCOV version 1.11