"Fossies" - the Fresh Open Source Software Archive

Member "gpgme-1.15.1/src/engine-gpg.c" (8 Jan 2021, 88959 Bytes) of package /linux/privat/gpgme-1.15.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "engine-gpg.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.15.0_vs_1.15.1.

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