LCOV - code coverage report
Current view: top level - src - gpgme-tool.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1468 0.0 %
Date: 2016-09-12 12:35:26 Functions: 0 129 0.0 %

          Line data    Source code
       1             : /* gpgme-tool.c - Assuan server exposing GnuPG Made Easy operations.
       2             :    Copyright (C) 2009, 2010, 2012, 2013 g10 Code GmbH
       3             :    Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
       4             : 
       5             :    This file is part of GPGME.
       6             : 
       7             :    GPGME is free software; you can redistribute it and/or modify it
       8             :    under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    GPGME is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #if HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : 
      25             : #include <stdio.h>
      26             : #include <stdlib.h>
      27             : #include <string.h>
      28             : #include <errno.h>
      29             : #include <getopt.h>
      30             : #include <ctype.h>
      31             : #include <stdarg.h>
      32             : #ifdef HAVE_LOCALE_H
      33             : #include <locale.h>
      34             : #endif
      35             : 
      36             : #include <assuan.h>
      37             : 
      38             : #include "argparse.h"
      39             : #include "gpgme.h"
      40             : 
      41             : /* GCC attributes.  */
      42             : #if __GNUC__ >= 4
      43             : # define GT_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
      44             : #else
      45             : # define GT_GCC_A_SENTINEL(a)
      46             : #endif
      47             : 
      48             : #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
      49             : # define GT_GCC_A_PRINTF(f, a)  __attribute__ ((format (printf,f,a)))
      50             : #else
      51             : # define GT_GCC_A_PRINTF(f, a)
      52             : #endif
      53             : 
      54             : #define DIM(v) (sizeof(v)/sizeof((v)[0]))
      55             : #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
      56             :                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
      57             : #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
      58             : 
      59             : 
      60             : 
      61             : /* MEMBUF */
      62             : 
      63             : /* A simple implementation of a dynamic buffer.  Use init_membuf() to
      64             :    create a buffer, put_membuf to append bytes and get_membuf to
      65             :    release and return the buffer.  Allocation errors are detected but
      66             :    only returned at the final get_membuf(), this helps not to clutter
      67             :    the code with out-of-core checks.  */
      68             : 
      69             : /* The definition of the structure is private, we only need it here,
      70             :    so it can be allocated on the stack. */
      71             : struct private_membuf_s
      72             : {
      73             :   size_t len;
      74             :   size_t size;
      75             :   char *buf;
      76             :   int out_of_core;
      77             : };
      78             : 
      79             : typedef struct private_membuf_s membuf_t;
      80             : 
      81             : /* Return the current length of the membuf.  */
      82             : #define get_membuf_len(a)  ((a)->len)
      83             : #define is_membuf_ready(a) ((a)->buf || (a)->out_of_core)
      84             : #define MEMBUF_ZERO        { 0, 0, NULL, 0}
      85             : 
      86             : 
      87             : static void
      88           0 : init_membuf (membuf_t *mb, int initiallen)
      89             : {
      90           0 :   mb->len = 0;
      91           0 :   mb->size = initiallen;
      92           0 :   mb->out_of_core = 0;
      93           0 :   mb->buf = malloc (initiallen);
      94           0 :   if (!mb->buf)
      95           0 :     mb->out_of_core = errno;
      96           0 : }
      97             : 
      98             : 
      99             : /* Shift the the content of the membuf MB by AMOUNT bytes.  The next
     100             :    operation will then behave as if AMOUNT bytes had not been put into
     101             :    the buffer.  If AMOUNT is greater than the actual accumulated
     102             :    bytes, the membuf is basically reset to its initial state.  */
     103             : #if 0 /* Not yet used.  */
     104             : static void
     105             : clear_membuf (membuf_t *mb, size_t amount)
     106             : {
     107             :   /* No need to clear if we are already out of core.  */
     108             :   if (mb->out_of_core)
     109             :     return;
     110             :   if (amount >= mb->len)
     111             :     mb->len = 0;
     112             :   else
     113             :     {
     114             :       mb->len -= amount;
     115             :       memmove (mb->buf, mb->buf+amount, mb->len);
     116             :     }
     117             : }
     118             : #endif /* unused */
     119             : 
     120             : static void
     121           0 : put_membuf (membuf_t *mb, const void *buf, size_t len)
     122             : {
     123           0 :   if (mb->out_of_core || !len)
     124           0 :     return;
     125             : 
     126           0 :   if (mb->len + len >= mb->size)
     127             :     {
     128             :       char *p;
     129             : 
     130           0 :       mb->size += len + 1024;
     131           0 :       p = realloc (mb->buf, mb->size);
     132           0 :       if (!p)
     133             :         {
     134           0 :           mb->out_of_core = errno ? errno : ENOMEM;
     135           0 :           return;
     136             :         }
     137           0 :       mb->buf = p;
     138             :     }
     139           0 :   memcpy (mb->buf + mb->len, buf, len);
     140           0 :   mb->len += len;
     141             : }
     142             : 
     143             : 
     144             : #if 0 /* Not yet used.  */
     145             : static void
     146             : put_membuf_str (membuf_t *mb, const char *string)
     147             : {
     148             :   put_membuf (mb, string, strlen (string));
     149             : }
     150             : #endif /* unused */
     151             : 
     152             : 
     153             : static void *
     154           0 : get_membuf (membuf_t *mb, size_t *len)
     155             : {
     156             :   char *p;
     157             : 
     158           0 :   if (mb->out_of_core)
     159             :     {
     160           0 :       if (mb->buf)
     161             :         {
     162           0 :           free (mb->buf);
     163           0 :           mb->buf = NULL;
     164             :         }
     165           0 :       gpg_err_set_errno (mb->out_of_core);
     166           0 :       return NULL;
     167             :     }
     168             : 
     169           0 :   p = mb->buf;
     170           0 :   if (len)
     171           0 :     *len = mb->len;
     172           0 :   mb->buf = NULL;
     173           0 :   mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
     174           0 :   return p;
     175             : }
     176             : 
     177             : 
     178             : /* Peek at the membuf MB.  On success a pointer to the buffer is
     179             :    returned which is valid until the next operation on MB.  If LEN is
     180             :    not NULL the current LEN of the buffer is stored there.  On error
     181             :    NULL is returned and ERRNO is set.  */
     182             : #if 0 /* Not yet used.  */
     183             : static const void *
     184             : peek_membuf (membuf_t *mb, size_t *len)
     185             : {
     186             :   const char *p;
     187             : 
     188             :   if (mb->out_of_core)
     189             :     {
     190             :       gpg_err_set_errno (mb->out_of_core);
     191             :       return NULL;
     192             :     }
     193             : 
     194             :   p = mb->buf;
     195             :   if (len)
     196             :     *len = mb->len;
     197             :   return p;
     198             : }
     199             : #endif /* unused */
     200             : 
     201             : 
     202             : 
     203             : /* SUPPORT.  */
     204             : FILE *log_stream;
     205             : char *program_name = "gpgme-tool";
     206             : 
     207             : #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
     208             : 
     209             : 
     210             : void log_error (int status, gpg_error_t errnum,
     211             :                 const char *fmt, ...) GT_GCC_A_PRINTF(3,4);
     212             : 
     213             : 
     214             : void
     215           0 : log_init (void)
     216             : {
     217           0 :   log_stream = stderr;
     218           0 : }
     219             : 
     220             : 
     221             : void
     222           0 : log_error (int status, gpg_error_t errnum, const char *fmt, ...)
     223             : {
     224             :   va_list ap;
     225             : 
     226           0 :   fprintf (log_stream, "%s: ", program_name);
     227           0 :   va_start (ap, fmt);
     228           0 :   vfprintf (log_stream, fmt, ap);
     229           0 :   va_end (ap);
     230           0 :   if (errnum)
     231             :     {
     232           0 :       fprintf (log_stream, ": %s", gpg_strerror (errnum));
     233           0 :       if (gpg_err_source (errnum) != GPG_ERR_SOURCE_GPGME)
     234           0 :         fprintf (log_stream, " <%s>", gpg_strsource (errnum));
     235             :     }
     236           0 :   fprintf (log_stream, "\n");
     237           0 :   if (status)
     238           0 :     exit (status);
     239           0 : }
     240             : 
     241             : 
     242             : /* Note that it is sufficient to allocate the target string D as long
     243             :    as the source string S, i.e.: strlen(s)+1;.  D == S is allowed.  */
     244             : static void
     245           0 : strcpy_escaped_plus (char *d, const char *s)
     246             : {
     247           0 :   while (*s)
     248             :     {
     249           0 :       if (*s == '%' && s[1] && s[2])
     250             :         {
     251           0 :           s++;
     252           0 :           *d++ = xtoi_2 (s);
     253           0 :           s += 2;
     254             :         }
     255           0 :       else if (*s == '+')
     256           0 :         *d++ = ' ', s++;
     257             :       else
     258           0 :         *d++ = *s++;
     259             :     }
     260           0 :   *d = 0;
     261           0 : }
     262             : 
     263             : 
     264             : /* Check whether the option NAME appears in LINE.  */
     265             : static int
     266           0 : has_option (const char *line, const char *name)
     267             : {
     268             :   const char *s;
     269           0 :   int n = strlen (name);
     270             : 
     271           0 :   s = strstr (line, name);
     272           0 :   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
     273             : }
     274             : 
     275             : /* Skip over options.  It is assumed that leading spaces have been
     276             :    removed (this is the case for lines passed to a handler from
     277             :    assuan).  Blanks after the options are also removed.  */
     278             : static char *
     279           0 : skip_options (char *line)
     280             : {
     281           0 :   while ( *line == '-' && line[1] == '-' )
     282             :     {
     283           0 :       while (*line && !spacep (line))
     284           0 :         line++;
     285           0 :       while (spacep (line))
     286           0 :         line++;
     287             :     }
     288           0 :   return line;
     289             : }
     290             : 
     291             : 
     292             : 
     293             : 
     294             : typedef gpg_error_t (*result_xml_write_cb_t) (void *hook, const void *buf,
     295             :                                               size_t len);
     296             : 
     297             : static char xml_preamble1[] = "<?xml version=\"1.0\" "
     298             :   "encoding=\"UTF-8\" standalone=\"yes\"?>\n";
     299             : static const char xml_preamble2[] = "<gpgme>\n";
     300             : static const char xml_end[] = "</gpgme>\n";
     301             : 
     302             : 
     303             : struct result_xml_state
     304             : {
     305             :   int indent;
     306             :   result_xml_write_cb_t cb;
     307             :   void *hook;
     308             : 
     309             : #define MAX_TAGS 20
     310             :   int next_tag;
     311             :   char *tag[MAX_TAGS];
     312             :   int had_data[MAX_TAGS];
     313             : };
     314             : 
     315             : 
     316             : void
     317           0 : result_init (struct result_xml_state *state, int indent,
     318             :              result_xml_write_cb_t cb, void *hook)
     319             : {
     320           0 :   memset (state, '\0', sizeof (*state));
     321           0 :   state->indent = indent;
     322           0 :   state->cb = cb;
     323           0 :   state->hook = hook;
     324           0 : }
     325             : 
     326             : 
     327             : gpg_error_t
     328           0 : result_xml_indent (struct result_xml_state *state)
     329             : {
     330           0 :   char spaces[state->indent + 1];
     331             :   int i;
     332           0 :   for (i = 0; i < state->indent; i++)
     333           0 :     spaces[i] = ' ';
     334           0 :   spaces[i] = '\0';
     335           0 :   return (*state->cb) (state->hook, spaces, i);
     336             : }
     337             : 
     338             : 
     339             : gpg_error_t
     340           0 : result_xml_tag_start (struct result_xml_state *state, char *name, ...)
     341             : {
     342           0 :   result_xml_write_cb_t cb = state->cb;
     343           0 :   void *hook = state->hook;
     344             :   va_list ap;
     345             :   char *attr;
     346             :   char *attr_val;
     347             : 
     348           0 :   va_start (ap, name);
     349             : 
     350           0 :   if (state->next_tag > 0)
     351             :     {
     352           0 :       if (! state->had_data[state->next_tag - 1])
     353             :         {
     354           0 :           (*cb) (hook, ">\n", 2);
     355           0 :           (*cb) (hook, NULL, 0);
     356             :         }
     357           0 :       state->had_data[state->next_tag - 1] = 1;
     358             :     }
     359             : 
     360           0 :   result_xml_indent (state);
     361           0 :   (*cb) (hook, "<", 1);
     362           0 :   (*cb) (hook, name, strlen (name));
     363             : 
     364           0 :   state->tag[state->next_tag] = name;
     365           0 :   state->had_data[state->next_tag] = 0;
     366           0 :   state->indent += 2;
     367           0 :   state->next_tag++;
     368             : 
     369             :   while (1)
     370             :     {
     371           0 :       attr = va_arg (ap, char *);
     372           0 :       if (attr == NULL)
     373           0 :         break;
     374             : 
     375           0 :       attr_val = va_arg (ap, char *);
     376           0 :       if (attr_val == NULL)
     377           0 :         attr_val = "(null)";
     378             : 
     379           0 :       (*cb) (hook, " ", 1);
     380           0 :       (*cb) (hook, attr, strlen (attr));
     381           0 :       (*cb) (hook, "=\"", 2);
     382           0 :       (*cb) (hook, attr_val, strlen (attr_val));
     383           0 :       (*cb) (hook, "\"", 1);
     384           0 :     }
     385           0 :   va_end (ap);
     386           0 :   return 0;
     387             : }
     388             : 
     389             : /* Return a constant string with an XML entity for C.  */
     390             : static const char *
     391           0 : result_xml_escape_replacement(char c)
     392             : {
     393           0 :   switch (c)
     394             :     {
     395             :     case '<':
     396           0 :       return "&lt;";
     397             :     case '>':
     398           0 :       return "&gt;";
     399             :     case '&':
     400           0 :       return "&amp;";
     401             :     default:
     402           0 :       return NULL;
     403             :     }
     404             : }
     405             : 
     406             : /* Escape DATA by replacing certain characters with their XML
     407             :    entities.  The result is stored in a newly allocated buffer which
     408             :    address will be stored at BUF.   Returns 0 on success. */
     409             : static gpg_error_t
     410           0 : result_xml_escape (const char *data, char **buf)
     411             : {
     412             :   int data_len, i;
     413             :   const char *r;
     414             :   membuf_t mb;
     415             : 
     416           0 :   init_membuf (&mb, 128);
     417           0 :   if (data)
     418             :     {
     419           0 :       data_len = strlen (data);
     420           0 :       for (i = 0; i < data_len; i++)
     421             :         {
     422           0 :           r = result_xml_escape_replacement (data[i]);
     423           0 :           if (r)
     424           0 :             put_membuf (&mb, r, strlen (r));
     425             :           else
     426           0 :             put_membuf (&mb, data+i, 1);
     427             :         }
     428             :     }
     429           0 :   put_membuf (&mb, "", 1);
     430           0 :   *buf = get_membuf (&mb, NULL);
     431           0 :   return *buf? 0 : gpg_error_from_syserror ();
     432             : }
     433             : 
     434             : 
     435             : gpg_error_t
     436           0 : result_xml_tag_data (struct result_xml_state *state, const char *data)
     437             : {
     438             :   gpg_error_t err;
     439           0 :   result_xml_write_cb_t cb = state->cb;
     440           0 :   void *hook = state->hook;
     441           0 :   char *buf = NULL;
     442             : 
     443           0 :   if (state->had_data[state->next_tag - 1])
     444             :     {
     445           0 :       (*cb) (hook, "\n", 2);
     446           0 :       (*cb) (hook, NULL, 0);
     447           0 :       result_xml_indent (state);
     448             :     }
     449             :   else
     450           0 :     (*cb) (hook, ">", 1);
     451           0 :   state->had_data[state->next_tag - 1] = 2;
     452             : 
     453           0 :   err = result_xml_escape (data, &buf);
     454           0 :   if (err)
     455           0 :     return err;
     456             : 
     457           0 :   (*cb) (hook, buf, strlen (buf));
     458             : 
     459           0 :   free (buf);
     460             : 
     461           0 :   return 0;
     462             : }
     463             : 
     464             : 
     465             : gpg_error_t
     466           0 : result_xml_tag_end (struct result_xml_state *state)
     467             : {
     468           0 :   result_xml_write_cb_t cb = state->cb;
     469           0 :   void *hook = state->hook;
     470             : 
     471           0 :   state->next_tag--;
     472           0 :   state->indent -= 2;
     473             : 
     474           0 :   if (state->had_data[state->next_tag])
     475             :     {
     476           0 :       if (state->had_data[state->next_tag] == 1)
     477           0 :         result_xml_indent (state);
     478           0 :       (*cb) (hook, "</", 2);
     479           0 :       (*cb) (hook, state->tag[state->next_tag],
     480           0 :              strlen (state->tag[state->next_tag]));
     481           0 :       (*cb) (hook, ">\n", 2);
     482           0 :       (*cb) (hook, NULL, 0);
     483             :     }
     484             :   else
     485             :     {
     486           0 :       (*cb) (hook, " />\n", 4);
     487           0 :       (*cb) (hook, NULL, 0);
     488             :     }
     489           0 :   return 0;
     490             : }
     491             : 
     492             : 
     493             : gpg_error_t
     494           0 : result_add_error (struct result_xml_state *state, char *name, gpg_error_t err)
     495             : {
     496             :   char code[20];
     497             :   char msg[1024];
     498           0 :   snprintf (code, sizeof (code) - 1, "0x%x", err);
     499           0 :   snprintf (msg, sizeof (msg) - 1, "%s <%s>",
     500             :             gpg_strerror (err), gpg_strsource (err));
     501           0 :   result_xml_tag_start (state, name, "value", code, NULL);
     502           0 :   result_xml_tag_data (state, msg);
     503           0 :   result_xml_tag_end (state);
     504           0 :   return 0;
     505             : }
     506             : 
     507             : 
     508             : gpg_error_t
     509           0 : result_add_pubkey_algo (struct result_xml_state *state,
     510             :                         char *name, gpgme_pubkey_algo_t algo)
     511             : {
     512             :   char code[20];
     513             :   char msg[80];
     514           0 :   snprintf (code, sizeof (code) - 1, "0x%x", algo);
     515           0 :   snprintf (msg, sizeof (msg) - 1, "%s",
     516             :             gpgme_pubkey_algo_name (algo));
     517           0 :   result_xml_tag_start (state, name, "value", code, NULL);
     518           0 :   result_xml_tag_data (state, msg);
     519           0 :   result_xml_tag_end (state);
     520           0 :   return 0;
     521             : }
     522             : 
     523             : 
     524             : gpg_error_t
     525           0 : result_add_hash_algo (struct result_xml_state *state,
     526             :                          char *name, gpgme_hash_algo_t algo)
     527             : {
     528             :   char code[20];
     529             :   char msg[80];
     530           0 :   snprintf (code, sizeof (code) - 1, "0x%x", algo);
     531           0 :   snprintf (msg, sizeof (msg) - 1, "%s",
     532             :             gpgme_hash_algo_name (algo));
     533           0 :   result_xml_tag_start (state, name, "value", code, NULL);
     534           0 :   result_xml_tag_data (state, msg);
     535           0 :   result_xml_tag_end (state);
     536           0 :   return 0;
     537             : }
     538             : 
     539             : 
     540             : gpg_error_t
     541           0 : result_add_keyid (struct result_xml_state *state, char *name, char *keyid)
     542             : {
     543           0 :   result_xml_tag_start (state, name, NULL);
     544           0 :   result_xml_tag_data (state, keyid);
     545           0 :   result_xml_tag_end (state);
     546           0 :   return 0;
     547             : }
     548             : 
     549             : 
     550             : gpg_error_t
     551           0 : result_add_fpr (struct result_xml_state *state, char *name, char *fpr)
     552             : {
     553           0 :   result_xml_tag_start (state, name, NULL);
     554           0 :   result_xml_tag_data (state, fpr);
     555           0 :   result_xml_tag_end (state);
     556           0 :   return 0;
     557             : }
     558             : 
     559             : 
     560             : gpg_error_t
     561           0 : result_add_timestamp (struct result_xml_state *state, char *name,
     562             :                       unsigned int timestamp)
     563             : {
     564             :   char code[20];
     565             : 
     566           0 :   snprintf (code, sizeof (code) - 1, "%ui", timestamp);
     567           0 :   result_xml_tag_start (state, name, "unix", code, NULL);
     568           0 :   result_xml_tag_end (state);
     569           0 :   return 0;
     570             : }
     571             : 
     572             : 
     573             : gpg_error_t
     574           0 : result_add_sig_mode (struct result_xml_state *state, char *name,
     575             :                      gpgme_sig_mode_t sig_mode)
     576             : {
     577             :   char *mode;
     578             :   char code[20];
     579             : 
     580           0 :   snprintf (code, sizeof (code) - 1, "%i", sig_mode);
     581           0 :   switch (sig_mode)
     582             :     {
     583             :     case GPGME_SIG_MODE_NORMAL:
     584           0 :       mode = "normal";
     585           0 :       break;
     586             :     case GPGME_SIG_MODE_DETACH:
     587           0 :       mode = "detach";
     588           0 :       break;
     589             :     case GPGME_SIG_MODE_CLEAR:
     590           0 :       mode = "clear";
     591           0 :       break;
     592             :     default:
     593           0 :       mode = "unknown";
     594             :     }
     595             : 
     596           0 :   result_xml_tag_start (state, name, "type", mode, "value", code, NULL);
     597           0 :   result_xml_tag_data (state, mode);
     598           0 :   result_xml_tag_end (state);
     599           0 :   return 0;
     600             : }
     601             : 
     602             : 
     603             : gpg_error_t
     604           0 : result_add_protocol (struct result_xml_state *state, char *name,
     605             :                      gpgme_protocol_t protocol)
     606             : {
     607             :   const char *str;
     608             :   char code[20];
     609             : 
     610           0 :   snprintf (code, sizeof (code) - 1, "%i", protocol);
     611           0 :   str = gpgme_get_protocol_name(protocol);
     612           0 :   if (!str)
     613           0 :     str = "invalid";
     614           0 :   result_xml_tag_start (state, name, "value", code, NULL);
     615           0 :   result_xml_tag_data (state, str);
     616           0 :   result_xml_tag_end (state);
     617           0 :   return 0;
     618             : }
     619             : 
     620             : 
     621             : gpg_error_t
     622           0 : result_add_validity (struct result_xml_state *state, char *name,
     623             :                      gpgme_validity_t validity)
     624             : {
     625             :   const char *str;
     626             :   char code[20];
     627             : 
     628           0 :   snprintf (code, sizeof (code) - 1, "%i", validity);
     629           0 :   switch (validity)
     630             :     {
     631             :     case GPGME_VALIDITY_UNDEFINED:
     632           0 :       str ="undefined";
     633           0 :       break;
     634             :     case GPGME_VALIDITY_NEVER:
     635           0 :       str ="never";
     636           0 :       break;
     637             :     case GPGME_VALIDITY_MARGINAL:
     638           0 :       str ="marginal";
     639           0 :       break;
     640             :     case GPGME_VALIDITY_FULL:
     641           0 :       str ="full";
     642           0 :       break;
     643             :     case GPGME_VALIDITY_ULTIMATE:
     644           0 :       str ="ultimate";
     645           0 :       break;
     646             :     default:
     647           0 :       str ="unknown";
     648             :     }
     649             : 
     650           0 :   result_xml_tag_start (state, name, "value", code, NULL);
     651           0 :   result_xml_tag_data (state, str);
     652           0 :   result_xml_tag_end (state);
     653           0 :   return 0;
     654             : }
     655             : 
     656             : 
     657             : gpg_error_t
     658           0 : result_add_value (struct result_xml_state *state,
     659             :                   char *name, unsigned int val)
     660             : {
     661             :   char code[20];
     662             : 
     663           0 :   snprintf (code, sizeof (code) - 1, "0x%x", val);
     664           0 :   result_xml_tag_start (state, name, "value", code, NULL);
     665           0 :   result_xml_tag_end (state);
     666           0 :   return 0;
     667             : }
     668             : 
     669             : 
     670             : gpg_error_t
     671           0 : result_add_string (struct result_xml_state *state,
     672             :                    char *name, char *str)
     673             : {
     674           0 :   if (!str)
     675           0 :     str = "";
     676           0 :   result_xml_tag_start (state, name, NULL);
     677           0 :   result_xml_tag_data (state, str);
     678           0 :   result_xml_tag_end (state);
     679           0 :   return 0;
     680             : }
     681             : 
     682             : 
     683             : gpg_error_t
     684           0 : result_encrypt_to_xml (gpgme_ctx_t ctx, int indent,
     685             :                        result_xml_write_cb_t cb, void *hook)
     686             : {
     687             :   struct result_xml_state state;
     688           0 :   gpgme_encrypt_result_t res = gpgme_op_encrypt_result (ctx);
     689             :   gpgme_invalid_key_t inv_recp;
     690             : 
     691           0 :   if (! res)
     692           0 :     return 0;
     693             : 
     694           0 :   result_init (&state, indent, cb, hook);
     695           0 :   result_xml_tag_start (&state, "encrypt-result", NULL);
     696             : 
     697           0 :   inv_recp = res->invalid_recipients;
     698           0 :   if (inv_recp)
     699             :     {
     700           0 :       result_xml_tag_start (&state, "invalid-recipients", NULL);
     701             : 
     702           0 :       while (inv_recp)
     703             :         {
     704           0 :           result_xml_tag_start (&state, "invalid-key", NULL);
     705           0 :           if (inv_recp->fpr)
     706           0 :             result_add_fpr (&state, "fpr", inv_recp->fpr);
     707           0 :           result_add_error (&state, "reason", inv_recp->reason);
     708           0 :           result_xml_tag_end (&state);
     709           0 :           inv_recp = inv_recp->next;
     710             :         }
     711           0 :       result_xml_tag_end (&state);
     712             :     }
     713           0 :   result_xml_tag_end (&state);
     714             : 
     715           0 :   return 0;
     716             : }
     717             : 
     718             : 
     719             : gpg_error_t
     720           0 : result_decrypt_to_xml (gpgme_ctx_t ctx, int indent,
     721             :                        result_xml_write_cb_t cb, void *hook)
     722             : {
     723             :   struct result_xml_state state;
     724           0 :   gpgme_decrypt_result_t res = gpgme_op_decrypt_result (ctx);
     725             :   gpgme_recipient_t recp;
     726             : 
     727           0 :   if (! res)
     728           0 :     return 0;
     729             : 
     730           0 :   result_init (&state, indent, cb, hook);
     731           0 :   result_xml_tag_start (&state, "decrypt-result", NULL);
     732             : 
     733           0 :   if (res->file_name)
     734             :     {
     735           0 :       result_xml_tag_start (&state, "file-name", NULL);
     736           0 :       result_xml_tag_data (&state, res->file_name);
     737           0 :       result_xml_tag_end (&state);
     738             :     }
     739           0 :   if (res->unsupported_algorithm)
     740             :     {
     741           0 :       result_xml_tag_start (&state, "unsupported-alogorithm", NULL);
     742           0 :       result_xml_tag_data (&state, res->unsupported_algorithm);
     743           0 :       result_xml_tag_end (&state);
     744             :     }
     745           0 :   if (res->wrong_key_usage)
     746             :     {
     747           0 :       result_xml_tag_start (&state, "wrong-key-usage", NULL);
     748           0 :       result_xml_tag_end (&state);
     749             :     }
     750             : 
     751           0 :   recp = res->recipients;
     752           0 :   if (recp)
     753             :     {
     754           0 :       result_xml_tag_start (&state, "recipients", NULL);
     755           0 :       while (recp)
     756             :         {
     757           0 :           result_xml_tag_start (&state, "recipient", NULL);
     758           0 :           result_add_keyid (&state, "keyid", recp->keyid);
     759           0 :           result_add_pubkey_algo (&state, "pubkey-algo", recp->pubkey_algo);
     760           0 :           result_add_error (&state, "status", recp->status);
     761           0 :           result_xml_tag_end (&state);
     762           0 :           recp = recp->next;
     763             :         }
     764           0 :       result_xml_tag_end (&state);
     765             :     }
     766           0 :   result_xml_tag_end (&state);
     767             : 
     768           0 :   return 0;
     769             : }
     770             : 
     771             : 
     772             : gpg_error_t
     773           0 : result_sign_to_xml (gpgme_ctx_t ctx, int indent,
     774             :                     result_xml_write_cb_t cb, void *hook)
     775             : {
     776             :   struct result_xml_state state;
     777           0 :   gpgme_sign_result_t res = gpgme_op_sign_result (ctx);
     778             :   gpgme_invalid_key_t inv_key;
     779             :   gpgme_new_signature_t new_sig;
     780             : 
     781           0 :   if (! res)
     782           0 :     return 0;
     783             : 
     784           0 :   result_init (&state, indent, cb, hook);
     785           0 :   result_xml_tag_start (&state, "sign-result", NULL);
     786             : 
     787           0 :   inv_key = res->invalid_signers;
     788           0 :   if (inv_key)
     789             :     {
     790           0 :       result_xml_tag_start (&state, "invalid-signers", NULL);
     791             : 
     792           0 :       while (inv_key)
     793             :         {
     794           0 :           result_xml_tag_start (&state, "invalid-key", NULL);
     795           0 :           if (inv_key->fpr)
     796           0 :             result_add_fpr (&state, "fpr", inv_key->fpr);
     797           0 :           result_add_error (&state, "reason", inv_key->reason);
     798           0 :           result_xml_tag_end (&state);
     799           0 :           inv_key = inv_key->next;
     800             :         }
     801           0 :       result_xml_tag_end (&state);
     802             :     }
     803             : 
     804           0 :   new_sig = res->signatures;
     805           0 :   if (new_sig)
     806             :     {
     807           0 :       result_xml_tag_start (&state, "signatures", NULL);
     808             : 
     809           0 :       while (new_sig)
     810             :         {
     811           0 :           result_xml_tag_start (&state, "new-signature", NULL);
     812           0 :           result_add_sig_mode (&state, "type", new_sig->type);
     813           0 :           result_add_pubkey_algo (&state, "pubkey-algo", new_sig->pubkey_algo);
     814           0 :           result_add_hash_algo (&state, "hash-algo", new_sig->hash_algo);
     815           0 :           result_add_timestamp (&state, "timestamp", new_sig->timestamp);
     816           0 :           if (new_sig->fpr)
     817           0 :             result_add_fpr (&state, "fpr", new_sig->fpr);
     818           0 :           result_add_value (&state, "sig-class", new_sig->sig_class);
     819             : 
     820           0 :           result_xml_tag_end (&state);
     821           0 :           new_sig = new_sig->next;
     822             :         }
     823           0 :       result_xml_tag_end (&state);
     824             :     }
     825             : 
     826           0 :   result_xml_tag_end (&state);
     827             : 
     828           0 :   return 0;
     829             : }
     830             : 
     831             : 
     832             : gpg_error_t
     833           0 : result_verify_to_xml (gpgme_ctx_t ctx, int indent,
     834             :                       result_xml_write_cb_t cb, void *hook)
     835             : {
     836             :   struct result_xml_state state;
     837           0 :   gpgme_verify_result_t res = gpgme_op_verify_result (ctx);
     838             :   gpgme_signature_t sig;
     839             : 
     840           0 :   if (! res)
     841           0 :     return 0;
     842             : 
     843           0 :   result_init (&state, indent, cb, hook);
     844           0 :   result_xml_tag_start (&state, "verify-result", NULL);
     845             : 
     846           0 :   if (res->file_name)
     847             :     {
     848           0 :       result_xml_tag_start (&state, "file-name", NULL);
     849           0 :       result_xml_tag_data (&state, res->file_name);
     850           0 :       result_xml_tag_end (&state);
     851             :     }
     852             : 
     853           0 :   sig = res->signatures;
     854           0 :   if (sig)
     855             :     {
     856           0 :       result_xml_tag_start (&state, "signatures", NULL);
     857             : 
     858           0 :       while (sig)
     859             :         {
     860           0 :           result_xml_tag_start (&state, "signature", NULL);
     861             : 
     862             :           /* FIXME: Could be done better. */
     863           0 :           result_add_value (&state, "summary", sig->summary);
     864           0 :           if (sig->fpr)
     865           0 :             result_add_fpr (&state, "fpr", sig->fpr);
     866           0 :           result_add_error (&state, "status", sig->status);
     867             :           /* FIXME: notations */
     868           0 :           result_add_timestamp (&state, "timestamp", sig->timestamp);
     869           0 :           result_add_timestamp (&state, "exp-timestamp", sig->exp_timestamp);
     870           0 :           result_add_value (&state, "wrong-key-usage", sig->wrong_key_usage);
     871           0 :           result_add_value (&state, "pka-trust", sig->pka_trust);
     872           0 :           result_add_value (&state, "chain-model", sig->chain_model);
     873           0 :           result_add_value (&state, "validity", sig->validity);
     874           0 :           result_add_error (&state, "validity-reason", sig->validity_reason);
     875           0 :           result_add_pubkey_algo (&state, "pubkey-algo", sig->pubkey_algo);
     876           0 :           result_add_hash_algo (&state, "hash-algo", sig->hash_algo);
     877           0 :           if (sig->pka_address)
     878           0 :             result_add_string (&state, "pka_address", sig->pka_address);
     879             : 
     880           0 :           result_xml_tag_end (&state);
     881           0 :           sig = sig->next;
     882             :         }
     883           0 :       result_xml_tag_end (&state);
     884             :     }
     885             : 
     886           0 :   result_xml_tag_end (&state);
     887             : 
     888           0 :   return 0;
     889             : }
     890             : 
     891             : 
     892             : gpg_error_t
     893           0 : result_import_to_xml (gpgme_ctx_t ctx, int indent,
     894             :                       result_xml_write_cb_t cb, void *hook)
     895             : {
     896             :   struct result_xml_state state;
     897           0 :   gpgme_import_result_t res = gpgme_op_import_result (ctx);
     898             :   gpgme_import_status_t stat;
     899             : 
     900           0 :   if (! res)
     901           0 :     return 0;
     902             : 
     903           0 :   result_init (&state, indent, cb, hook);
     904           0 :   result_xml_tag_start (&state, "import-result", NULL);
     905             : 
     906           0 :   result_add_value (&state, "considered", res->considered);
     907           0 :   result_add_value (&state, "no-user-id", res->no_user_id);
     908           0 :   result_add_value (&state, "imported", res->imported);
     909           0 :   result_add_value (&state, "imported-rsa", res->imported_rsa);
     910           0 :   result_add_value (&state, "unchanged", res->unchanged);
     911           0 :   result_add_value (&state, "new-user-ids", res->new_user_ids);
     912           0 :   result_add_value (&state, "new-sub-keys", res->new_sub_keys);
     913           0 :   result_add_value (&state, "new-signatures", res->new_signatures);
     914           0 :   result_add_value (&state, "new-revocations", res->new_revocations);
     915           0 :   result_add_value (&state, "secret-read", res->secret_read);
     916           0 :   result_add_value (&state, "secret-imported", res->secret_imported);
     917           0 :   result_add_value (&state, "secret-unchanged", res->secret_unchanged);
     918           0 :   result_add_value (&state, "skipped-new-keys", res->skipped_new_keys);
     919           0 :   result_add_value (&state, "not-imported", res->not_imported);
     920             : 
     921           0 :   stat = res->imports;
     922           0 :   if (stat)
     923             :     {
     924           0 :       result_xml_tag_start (&state, "imports", NULL);
     925             : 
     926           0 :       while (stat)
     927             :         {
     928           0 :           result_xml_tag_start (&state, "import-status", NULL);
     929             : 
     930           0 :           if (stat->fpr)
     931           0 :             result_add_fpr (&state, "fpr", stat->fpr);
     932           0 :           result_add_error (&state, "result", stat->result);
     933             :           /* FIXME: Could be done better. */
     934           0 :           result_add_value (&state, "status", stat->status);
     935             : 
     936           0 :           result_xml_tag_end (&state);
     937           0 :           stat = stat->next;
     938             :         }
     939           0 :       result_xml_tag_end (&state);
     940             :     }
     941             : 
     942           0 :   result_xml_tag_end (&state);
     943             : 
     944           0 :   return 0;
     945             : }
     946             : 
     947             : 
     948             : gpg_error_t
     949           0 : result_genkey_to_xml (gpgme_ctx_t ctx, int indent,
     950             :                       result_xml_write_cb_t cb, void *hook)
     951             : {
     952             :   struct result_xml_state state;
     953           0 :   gpgme_genkey_result_t res = gpgme_op_genkey_result (ctx);
     954             : 
     955           0 :   if (! res)
     956           0 :     return 0;
     957             : 
     958           0 :   result_init (&state, indent, cb, hook);
     959           0 :   result_xml_tag_start (&state, "genkey-result", NULL);
     960             : 
     961           0 :   result_add_value (&state, "primary", res->primary);
     962           0 :   result_add_value (&state, "sub", res->sub);
     963           0 :   if (res->fpr)
     964           0 :     result_add_fpr (&state, "fpr", res->fpr);
     965             : 
     966           0 :   result_xml_tag_end (&state);
     967             : 
     968           0 :   return 0;
     969             : }
     970             : 
     971             : 
     972             : gpg_error_t
     973           0 : result_keylist_to_xml (gpgme_ctx_t ctx, int indent,
     974             :                       result_xml_write_cb_t cb, void *hook)
     975             : {
     976             :   struct result_xml_state state;
     977           0 :   gpgme_keylist_result_t res = gpgme_op_keylist_result (ctx);
     978             : 
     979           0 :   if (! res)
     980           0 :     return 0;
     981             : 
     982           0 :   result_init (&state, indent, cb, hook);
     983           0 :   result_xml_tag_start (&state, "keylist-result", NULL);
     984             : 
     985           0 :   result_add_value (&state, "truncated", res->truncated);
     986             : 
     987           0 :   result_xml_tag_end (&state);
     988             : 
     989           0 :   return 0;
     990             : }
     991             : 
     992             : 
     993             : gpg_error_t
     994           0 : result_vfs_mount_to_xml (gpgme_ctx_t ctx, int indent,
     995             :                          result_xml_write_cb_t cb, void *hook)
     996             : {
     997             :   struct result_xml_state state;
     998           0 :   gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result (ctx);
     999             : 
    1000           0 :   if (! res)
    1001           0 :     return 0;
    1002             : 
    1003           0 :   result_init (&state, indent, cb, hook);
    1004           0 :   result_xml_tag_start (&state, "vfs-mount-result", NULL);
    1005             : 
    1006           0 :   result_add_string (&state, "mount-dir", res->mount_dir);
    1007             : 
    1008           0 :   result_xml_tag_end (&state);
    1009             : 
    1010           0 :   return 0;
    1011             : }
    1012             : 
    1013             : 
    1014             : typedef enum status
    1015             :   {
    1016             :     STATUS_PROTOCOL,
    1017             :     STATUS_PROGRESS,
    1018             :     STATUS_ENGINE,
    1019             :     STATUS_ARMOR,
    1020             :     STATUS_TEXTMODE,
    1021             :     STATUS_INCLUDE_CERTS,
    1022             :     STATUS_KEYLIST_MODE,
    1023             :     STATUS_RECIPIENT,
    1024             :     STATUS_ENCRYPT_RESULT,
    1025             :     STATUS_IDENTIFY_RESULT
    1026             :   } status_t;
    1027             : 
    1028             : const char *status_string[] =
    1029             :   {
    1030             :     "PROTOCOL",
    1031             :     "PROGRESS",
    1032             :     "ENGINE",
    1033             :     "ARMOR",
    1034             :     "TEXTMODE",
    1035             :     "INCLUDE_CERTS",
    1036             :     "KEYLIST_MODE",
    1037             :     "RECIPIENT",
    1038             :     "ENCRYPT_RESULT",
    1039             :     "IDENTIFY_RESULT"
    1040             :   };
    1041             : 
    1042             : struct gpgme_tool
    1043             : {
    1044             :   gpgme_ctx_t ctx;
    1045             : #define MAX_RECIPIENTS 10
    1046             :   gpgme_key_t recipients[MAX_RECIPIENTS + 1];
    1047             :   int recipients_nr;
    1048             : 
    1049             :   gpg_error_t (*write_status) (void *hook, const char *status, const char *msg);
    1050             :   void *write_status_hook;
    1051             :   gpg_error_t (*write_data) (void *hook, const void *buf, size_t len);
    1052             :   void *write_data_hook;
    1053             : };
    1054             : typedef struct gpgme_tool *gpgme_tool_t;
    1055             : 
    1056             : 
    1057             : /* Forward declaration.  */
    1058             : void gt_write_status (gpgme_tool_t gt,
    1059             :                       status_t status, ...) GT_GCC_A_SENTINEL(0);
    1060             : static gpg_error_t
    1061             : server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
    1062             :                       int was_bad, int fd);
    1063             : 
    1064             : 
    1065             : void
    1066           0 : _gt_progress_cb (void *opaque, const char *what,
    1067             :                  int type, int current, int total)
    1068             : {
    1069           0 :   gpgme_tool_t gt = opaque;
    1070             :   char buf[100];
    1071             : 
    1072           0 :   snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total);
    1073           0 :   gt_write_status (gt, STATUS_PROGRESS, what, buf, NULL);
    1074           0 : }
    1075             : 
    1076             : 
    1077             : gpg_error_t
    1078           0 : _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
    1079             : {
    1080             :   gpg_error_t err;
    1081             : 
    1082           0 :   err = gpgme_new (ctx);
    1083           0 :   if (err)
    1084           0 :     return err;
    1085           0 :   gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt);
    1086           0 :   return 0;
    1087             : }
    1088             : 
    1089             : 
    1090             : void
    1091           0 : gt_init (gpgme_tool_t gt)
    1092             : {
    1093             :   gpg_error_t err;
    1094             : 
    1095           0 :   memset (gt, '\0', sizeof (*gt));
    1096             : 
    1097           0 :   err = _gt_gpgme_new (gt, &gt->ctx);
    1098           0 :   if (err)
    1099           0 :     log_error (1, err, "can't create gpgme context");
    1100           0 : }
    1101             : 
    1102             : 
    1103             : gpg_error_t
    1104           0 : gt_signers_add (gpgme_tool_t gt, const char *fpr)
    1105             : {
    1106             :   gpg_error_t err;
    1107             :   gpgme_key_t key;
    1108             : 
    1109           0 :   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
    1110           0 :   if (err)
    1111           0 :     return err;
    1112             : 
    1113           0 :   return gpgme_signers_add (gt->ctx, key);
    1114             : }
    1115             : 
    1116             : 
    1117             : gpg_error_t
    1118           0 : gt_signers_clear (gpgme_tool_t gt)
    1119             : {
    1120           0 :   gpgme_signers_clear (gt->ctx);
    1121           0 :   return 0;
    1122             : }
    1123             : 
    1124             : 
    1125             : gpg_error_t
    1126           0 : gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
    1127             : {
    1128             :   gpgme_ctx_t ctx;
    1129             :   gpgme_ctx_t listctx;
    1130             :   gpgme_error_t err;
    1131             :   gpgme_key_t key;
    1132             : 
    1133           0 :   if (!gt || !r_key || !pattern)
    1134           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    1135             : 
    1136           0 :   ctx = gt->ctx;
    1137             : 
    1138           0 :   err = gpgme_new (&listctx);
    1139           0 :   if (err)
    1140           0 :     return err;
    1141             : 
    1142             :   {
    1143             :     gpgme_protocol_t proto;
    1144             :     gpgme_engine_info_t info;
    1145             : 
    1146             :     /* Clone the relevant state.  */
    1147           0 :     proto = gpgme_get_protocol (ctx);
    1148             :     /* The g13 protocol does not allow keylisting, we need to choose
    1149             :        something else.  */
    1150           0 :     if (proto == GPGME_PROTOCOL_G13)
    1151           0 :       proto = GPGME_PROTOCOL_OpenPGP;
    1152             : 
    1153           0 :     gpgme_set_protocol (listctx, proto);
    1154           0 :     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
    1155           0 :     info = gpgme_ctx_get_engine_info (ctx);
    1156           0 :     while (info && info->protocol != proto)
    1157           0 :       info = info->next;
    1158           0 :     if (info)
    1159           0 :       gpgme_ctx_set_engine_info (listctx, proto,
    1160           0 :                                  info->file_name, info->home_dir);
    1161             :   }
    1162             : 
    1163           0 :   err = gpgme_op_keylist_start (listctx, pattern, 0);
    1164           0 :   if (!err)
    1165           0 :     err = gpgme_op_keylist_next (listctx, r_key);
    1166           0 :   if (!err)
    1167             :     {
    1168             :     try_next_key:
    1169           0 :       err = gpgme_op_keylist_next (listctx, &key);
    1170           0 :       if (gpgme_err_code (err) == GPG_ERR_EOF)
    1171           0 :         err = 0;
    1172             :       else
    1173             :         {
    1174           0 :           if (!err
    1175           0 :               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
    1176           0 :               && key && key->subkeys && key->subkeys->fpr
    1177           0 :               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
    1178             :             {
    1179             :               /* The fingerprint is identical.  We assume that this is
    1180             :                  the same key and don't mark it as an ambiguous.  This
    1181             :                  problem may occur with corrupted keyrings and has
    1182             :                  been noticed often with gpgsm.  In fact gpgsm uses a
    1183             :                  similar hack to sort out such duplicates but it can't
    1184             :                  do that while listing keys.  */
    1185           0 :               gpgme_key_unref (key);
    1186           0 :               goto try_next_key;
    1187             :             }
    1188           0 :           if (!err)
    1189             :             {
    1190           0 :               gpgme_key_unref (key);
    1191           0 :               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
    1192             :             }
    1193           0 :           gpgme_key_unref (*r_key);
    1194             :         }
    1195             :     }
    1196           0 :   gpgme_release (listctx);
    1197             : 
    1198           0 :   if (! err)
    1199           0 :     gt_write_status (gt, STATUS_RECIPIENT,
    1200           0 :                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
    1201           0 :                      (*r_key)->subkeys->fpr : "invalid", NULL);
    1202           0 :   return err;
    1203             : }
    1204             : 
    1205             : 
    1206             : gpg_error_t
    1207           0 : gt_recipients_add (gpgme_tool_t gt, const char *pattern)
    1208             : {
    1209             :   gpg_error_t err;
    1210             :   gpgme_key_t key;
    1211             : 
    1212           0 :   if (gt->recipients_nr >= MAX_RECIPIENTS)
    1213           0 :     return gpg_error (GPG_ERR_ENOMEM);
    1214             : 
    1215           0 :   if (gpgme_get_protocol (gt->ctx) == GPGME_PROTOCOL_UISERVER)
    1216           0 :     err = gpgme_key_from_uid (&key, pattern);
    1217             :   else
    1218           0 :     err = gt_get_key (gt, pattern, &key);
    1219           0 :   if (err)
    1220           0 :     return err;
    1221             : 
    1222           0 :   gt->recipients[gt->recipients_nr++] = key;
    1223           0 :   return 0;
    1224             : }
    1225             : 
    1226             : 
    1227             : void
    1228           0 : gt_recipients_clear (gpgme_tool_t gt)
    1229             : {
    1230             :   int idx;
    1231             : 
    1232           0 :   for (idx = 0; idx < gt->recipients_nr; idx++)
    1233           0 :     gpgme_key_unref (gt->recipients[idx]);
    1234           0 :   memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t));
    1235           0 :   gt->recipients_nr = 0;
    1236           0 : }
    1237             : 
    1238             : 
    1239             : gpg_error_t
    1240           0 : gt_reset (gpgme_tool_t gt)
    1241             : {
    1242             :   gpg_error_t err;
    1243             :   gpgme_ctx_t ctx;
    1244             : 
    1245           0 :   err = _gt_gpgme_new (gt, &ctx);
    1246           0 :   if (err)
    1247           0 :     return err;
    1248             : 
    1249           0 :   gpgme_release (gt->ctx);
    1250           0 :   gt->ctx = ctx;
    1251           0 :   gt_recipients_clear (gt);
    1252           0 :   return 0;
    1253             : }
    1254             : 
    1255             : 
    1256             : void
    1257           0 : gt_write_status (gpgme_tool_t gt, status_t status, ...)
    1258             : {
    1259             :   va_list ap;
    1260             :   const char *text;
    1261             :   char buf[950];
    1262             :   char *p;
    1263             :   size_t n;
    1264             :   gpg_error_t err;
    1265             : 
    1266           0 :   va_start (ap, status);
    1267           0 :   p = buf;
    1268           0 :   n = 0;
    1269           0 :   while ((text = va_arg (ap, const char *)))
    1270             :     {
    1271           0 :       if (n)
    1272             :         {
    1273           0 :           *p++ = ' ';
    1274           0 :           n++;
    1275             :         }
    1276           0 :       while (*text && n < sizeof (buf) - 2)
    1277             :         {
    1278           0 :           *p++ = *text++;
    1279           0 :           n++;
    1280             :         }
    1281             :     }
    1282           0 :   *p = 0;
    1283           0 :   va_end (ap);
    1284             : 
    1285           0 :   err = gt->write_status (gt->write_status_hook, status_string[status], buf);
    1286           0 :   if (err)
    1287           0 :     log_error (1, err, "can't write status line");
    1288           0 : }
    1289             : 
    1290             : 
    1291             : gpg_error_t
    1292           0 : gt_write_data (gpgme_tool_t gt, const void *buf, size_t len)
    1293             : {
    1294           0 :   return gt->write_data (gt->write_data_hook, buf, len);
    1295             : }
    1296             : 
    1297             : 
    1298             : gpg_error_t
    1299           0 : gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto)
    1300             : {
    1301             :   gpgme_engine_info_t info;
    1302           0 :   info = gpgme_ctx_get_engine_info (gt->ctx);
    1303           0 :   while (info)
    1304             :     {
    1305           0 :       if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol)
    1306           0 :         gt_write_status (gt, STATUS_ENGINE,
    1307             :                          gpgme_get_protocol_name (info->protocol),
    1308             :                          info->file_name, info->version,
    1309             :                          info->req_version, info->home_dir, NULL);
    1310           0 :       info = info->next;
    1311             :     }
    1312           0 :   return 0;
    1313             : }
    1314             : 
    1315             : 
    1316             : gpgme_protocol_t
    1317           0 : gt_protocol_from_name (const char *name)
    1318             : {
    1319           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP)))
    1320           0 :     return GPGME_PROTOCOL_OpenPGP;
    1321           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS)))
    1322           0 :     return GPGME_PROTOCOL_CMS;
    1323           0 :   if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF)))
    1324           0 :     return GPGME_PROTOCOL_GPGCONF;
    1325           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN)))
    1326           0 :     return GPGME_PROTOCOL_ASSUAN;
    1327           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13)))
    1328           0 :     return GPGME_PROTOCOL_G13;
    1329           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
    1330           0 :     return GPGME_PROTOCOL_UISERVER;
    1331           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_SPAWN)))
    1332           0 :     return GPGME_PROTOCOL_SPAWN;
    1333           0 :   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
    1334           0 :     return GPGME_PROTOCOL_DEFAULT;
    1335           0 :   return GPGME_PROTOCOL_UNKNOWN;
    1336             : }
    1337             : 
    1338             : 
    1339             : gpg_error_t
    1340           0 : gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
    1341             : {
    1342           0 :   return gpgme_set_protocol (gt->ctx, proto);
    1343             : }
    1344             : 
    1345             : 
    1346             : gpg_error_t
    1347           0 : gt_get_protocol (gpgme_tool_t gt)
    1348             : {
    1349           0 :   gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx);
    1350             : 
    1351           0 :   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
    1352             :                    NULL);
    1353             : 
    1354           0 :   return 0;
    1355             : }
    1356             : 
    1357             : 
    1358             : gpg_error_t
    1359           0 : gt_set_sub_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
    1360             : {
    1361           0 :   return gpgme_set_sub_protocol (gt->ctx, proto);
    1362             : }
    1363             : 
    1364             : 
    1365             : gpg_error_t
    1366           0 : gt_get_sub_protocol (gpgme_tool_t gt)
    1367             : {
    1368           0 :   gpgme_protocol_t proto = gpgme_get_sub_protocol (gt->ctx);
    1369             : 
    1370           0 :   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
    1371             :                    NULL);
    1372             : 
    1373           0 :   return 0;
    1374             : }
    1375             : 
    1376             : 
    1377             : gpg_error_t
    1378           0 : gt_set_pinentry_mode (gpgme_tool_t gt, gpgme_pinentry_mode_t mode, void *opaque)
    1379             : {
    1380             :   gpg_error_t err;
    1381             : 
    1382           0 :   gpgme_set_passphrase_cb (gt->ctx, NULL, NULL);
    1383           0 :   err = gpgme_set_pinentry_mode (gt->ctx, mode);
    1384           0 :   if (!err && mode == GPGME_PINENTRY_MODE_LOOPBACK)
    1385           0 :     gpgme_set_passphrase_cb (gt->ctx, server_passphrase_cb, opaque);
    1386           0 :   return err;
    1387             : }
    1388             : 
    1389             : 
    1390             : gpg_error_t
    1391           0 : gt_set_armor (gpgme_tool_t gt, int armor)
    1392             : {
    1393           0 :   gpgme_set_armor (gt->ctx, armor);
    1394           0 :   return 0;
    1395             : }
    1396             : 
    1397             : 
    1398             : gpg_error_t
    1399           0 : gt_get_armor (gpgme_tool_t gt)
    1400             : {
    1401           0 :   gt_write_status (gt, STATUS_ARMOR,
    1402           0 :                    gpgme_get_armor (gt->ctx) ? "true" : "false", NULL);
    1403             : 
    1404           0 :   return 0;
    1405             : }
    1406             : 
    1407             : 
    1408             : gpg_error_t
    1409           0 : gt_set_textmode (gpgme_tool_t gt, int textmode)
    1410             : {
    1411           0 :   gpgme_set_textmode (gt->ctx, textmode);
    1412           0 :   return 0;
    1413             : }
    1414             : 
    1415             : 
    1416             : gpg_error_t
    1417           0 : gt_get_textmode (gpgme_tool_t gt)
    1418             : {
    1419           0 :   gt_write_status (gt, STATUS_TEXTMODE,
    1420           0 :                    gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL);
    1421             : 
    1422           0 :   return 0;
    1423             : }
    1424             : 
    1425             : 
    1426             : gpg_error_t
    1427           0 : gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode)
    1428             : {
    1429           0 :   gpgme_set_keylist_mode (gt->ctx, keylist_mode);
    1430           0 :   return 0;
    1431             : }
    1432             : 
    1433             : 
    1434             : gpg_error_t
    1435           0 : gt_get_keylist_mode (gpgme_tool_t gt)
    1436             : {
    1437             : #define NR_KEYLIST_MODES 6
    1438             :   const char *modes[NR_KEYLIST_MODES + 1];
    1439           0 :   int idx = 0;
    1440           0 :   gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx);
    1441             : 
    1442           0 :   if (mode & GPGME_KEYLIST_MODE_LOCAL)
    1443           0 :     modes[idx++] = "local";
    1444           0 :   if (mode & GPGME_KEYLIST_MODE_EXTERN)
    1445           0 :     modes[idx++] = "extern";
    1446           0 :   if (mode & GPGME_KEYLIST_MODE_SIGS)
    1447           0 :     modes[idx++] = "sigs";
    1448           0 :   if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)
    1449           0 :     modes[idx++] = "sig_notations";
    1450           0 :   if (mode & GPGME_KEYLIST_MODE_WITH_SECRET)
    1451           0 :     modes[idx++] = "with_secret";
    1452           0 :   if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
    1453           0 :     modes[idx++] = "ephemeral";
    1454           0 :   if (mode & GPGME_KEYLIST_MODE_VALIDATE)
    1455           0 :     modes[idx++] = "validate";
    1456           0 :   modes[idx++] = NULL;
    1457             : 
    1458           0 :   gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
    1459             :                    modes[3], modes[4], modes[5], modes[6], NULL);
    1460             : 
    1461           0 :   return 0;
    1462             : }
    1463             : 
    1464             : 
    1465             : gpg_error_t
    1466           0 : gt_set_include_certs (gpgme_tool_t gt, int include_certs)
    1467             : {
    1468           0 :   gpgme_set_include_certs (gt->ctx, include_certs);
    1469           0 :   return 0;
    1470             : }
    1471             : 
    1472             : 
    1473             : gpg_error_t
    1474           0 : gt_get_include_certs (gpgme_tool_t gt)
    1475             : {
    1476           0 :   int include_certs = gpgme_get_include_certs (gt->ctx);
    1477             :   char buf[100];
    1478             : 
    1479           0 :   if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
    1480           0 :     strcpy (buf, "default");
    1481             :   else
    1482           0 :     snprintf (buf, sizeof (buf), "%i", include_certs);
    1483             : 
    1484           0 :   gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
    1485             : 
    1486           0 :   return 0;
    1487             : }
    1488             : 
    1489             : 
    1490             : gpg_error_t
    1491           0 : gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
    1492             :                    int verify)
    1493             : {
    1494           0 :   if (verify)
    1495           0 :     return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
    1496             :   else
    1497           0 :     return gpgme_op_decrypt (gt->ctx, cipher, plain);
    1498             : }
    1499             : 
    1500             : 
    1501             : gpg_error_t
    1502           0 : gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
    1503             :                  gpgme_data_t plain, gpgme_data_t cipher, int sign)
    1504             : {
    1505             :   gpg_error_t err;
    1506             :   gpgme_key_t *recp;
    1507             : 
    1508           0 :   recp = gt->recipients_nr? gt->recipients : NULL;
    1509             : 
    1510           0 :   if (sign)
    1511           0 :     err = gpgme_op_encrypt_sign (gt->ctx, recp, flags, plain, cipher);
    1512             :   else
    1513           0 :     err = gpgme_op_encrypt (gt->ctx, recp, flags, plain, cipher);
    1514             : 
    1515           0 :   gt_recipients_clear (gt);
    1516             : 
    1517           0 :   return err;
    1518             : }
    1519             : 
    1520             : 
    1521             : gpg_error_t
    1522           0 : gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
    1523             :          gpgme_sig_mode_t mode)
    1524             : {
    1525           0 :   return gpgme_op_sign (gt->ctx, plain, sig, mode);
    1526             : }
    1527             : 
    1528             : 
    1529             : gpg_error_t
    1530           0 : gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
    1531             :            gpgme_data_t plain)
    1532             : {
    1533           0 :   return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
    1534             : }
    1535             : 
    1536             : 
    1537             : gpg_error_t
    1538           0 : gt_import (gpgme_tool_t gt, gpgme_data_t data)
    1539             : {
    1540           0 :   return gpgme_op_import (gt->ctx, data);
    1541             : }
    1542             : 
    1543             : 
    1544             : gpg_error_t
    1545           0 : gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
    1546             :            gpgme_data_t data)
    1547             : {
    1548           0 :   return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
    1549             : }
    1550             : 
    1551             : 
    1552             : gpg_error_t
    1553           0 : gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
    1554             :            gpgme_data_t secret)
    1555             : {
    1556           0 :   return gpgme_op_genkey (gt->ctx, parms, public, secret);
    1557             : }
    1558             : 
    1559             : 
    1560             : gpg_error_t
    1561           0 : gt_import_keys (gpgme_tool_t gt, char *fpr[])
    1562             : {
    1563           0 :   gpg_error_t err = 0;
    1564             :   int cnt;
    1565             :   int idx;
    1566             :   gpgme_key_t *keys;
    1567             : 
    1568           0 :   cnt = 0;
    1569           0 :   while (fpr[cnt])
    1570           0 :     cnt++;
    1571             : 
    1572           0 :   if (! cnt)
    1573           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    1574             : 
    1575           0 :   keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
    1576           0 :   if (! keys)
    1577           0 :     return gpg_error_from_syserror ();
    1578             : 
    1579           0 :   for (idx = 0; idx < cnt; idx++)
    1580             :     {
    1581           0 :       err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
    1582           0 :       if (err)
    1583           0 :         break;
    1584             :     }
    1585           0 :   if (! err)
    1586             :     {
    1587           0 :       keys[cnt] = NULL;
    1588           0 :       err = gpgme_op_import_keys (gt->ctx, keys);
    1589             :     }
    1590             : 
    1591             :   /* Rollback.  */
    1592           0 :   while (--idx >= 0)
    1593           0 :     gpgme_key_unref (keys[idx]);
    1594           0 :   free (keys);
    1595             : 
    1596           0 :   return err;
    1597             : }
    1598             : 
    1599             : 
    1600             : gpg_error_t
    1601           0 : gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
    1602             : {
    1603             :   gpg_error_t err;
    1604             :   gpgme_key_t key;
    1605             : 
    1606           0 :   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
    1607           0 :   if (err)
    1608           0 :     return err;
    1609             : 
    1610           0 :   err = gpgme_op_delete (gt->ctx, key, allow_secret);
    1611           0 :   gpgme_key_unref (key);
    1612           0 :   return err;
    1613             : }
    1614             : 
    1615             : 
    1616             : gpg_error_t
    1617           0 : gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
    1618             : {
    1619           0 :   return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
    1620             : }
    1621             : 
    1622             : 
    1623             : gpg_error_t
    1624           0 : gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
    1625             : {
    1626           0 :   return gpgme_op_keylist_next (gt->ctx, key);
    1627             : }
    1628             : 
    1629             : 
    1630             : gpg_error_t
    1631           0 : gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
    1632             : {
    1633           0 :   return gpgme_op_getauditlog (gt->ctx, output, flags);
    1634             : }
    1635             : 
    1636             : 
    1637             : gpg_error_t
    1638           0 : gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
    1639             :               const char *mount_dir, int flags)
    1640             : {
    1641             :   gpg_error_t err;
    1642             :   gpg_error_t op_err;
    1643           0 :   err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
    1644           0 :   return err ? err : op_err;
    1645             : }
    1646             : 
    1647             : 
    1648             : gpg_error_t
    1649           0 : gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
    1650             : {
    1651             :   gpg_error_t err;
    1652             :   gpg_error_t op_err;
    1653           0 :   err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
    1654             :                              flags, &op_err);
    1655           0 :   gt_recipients_clear (gt);
    1656           0 :   return err ? err : op_err;
    1657             : }
    1658             : 
    1659             : 
    1660             : gpg_error_t
    1661           0 : gt_passwd (gpgme_tool_t gt, char *fpr)
    1662             : {
    1663             :   gpg_error_t err;
    1664             :   gpgme_key_t key;
    1665             : 
    1666           0 :   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
    1667           0 :   if (err)
    1668           0 :     return gpg_err_code (err) == GPG_ERR_EOF? gpg_error (GPG_ERR_NO_PUBKEY):err;
    1669             : 
    1670           0 :   err = gpgme_op_passwd (gt->ctx, key, 0);
    1671           0 :   gpgme_key_unref (key);
    1672           0 :   return err;
    1673             : }
    1674             : 
    1675             : 
    1676             : gpg_error_t
    1677           0 : gt_identify (gpgme_tool_t gt, gpgme_data_t data)
    1678             : {
    1679           0 :   const char *s = "?";
    1680             : 
    1681           0 :   switch (gpgme_data_identify (data, 0))
    1682             :     {
    1683           0 :     case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
    1684           0 :     case GPGME_DATA_TYPE_UNKNOWN      : s = "unknown"; break;
    1685           0 :     case GPGME_DATA_TYPE_PGP_SIGNED   : s = "PGP-signed"; break;
    1686           0 :     case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
    1687           0 :     case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
    1688           0 :     case GPGME_DATA_TYPE_PGP_OTHER    : s = "PGP"; break;
    1689           0 :     case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
    1690           0 :     case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
    1691           0 :     case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
    1692           0 :     case GPGME_DATA_TYPE_CMS_OTHER    : s = "CMS"; break;
    1693           0 :     case GPGME_DATA_TYPE_X509_CERT    : s = "X.509"; break;
    1694           0 :     case GPGME_DATA_TYPE_PKCS12       : s = "PKCS12"; break;
    1695             :     }
    1696           0 :   gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
    1697           0 :   return 0;
    1698             : }
    1699             : 
    1700             : 
    1701             : gpg_error_t
    1702           0 : gt_spawn (gpgme_tool_t gt, const char *pgm,
    1703             :           gpgme_data_t inp, gpgme_data_t outp)
    1704             : {
    1705             :   gpg_error_t err;
    1706             : 
    1707           0 :   err = gpgme_op_spawn (gt->ctx, pgm, NULL, inp, outp, outp, 0);
    1708             : 
    1709           0 :   return err;
    1710             : }
    1711             : 
    1712             : 
    1713             : #define GT_RESULT_ENCRYPT 0x1
    1714             : #define GT_RESULT_DECRYPT 0x2
    1715             : #define GT_RESULT_SIGN 0x4
    1716             : #define GT_RESULT_VERIFY 0x8
    1717             : #define GT_RESULT_IMPORT 0x10
    1718             : #define GT_RESULT_GENKEY 0x20
    1719             : #define GT_RESULT_KEYLIST 0x40
    1720             : #define GT_RESULT_VFS_MOUNT 0x80
    1721             : #define GT_RESULT_ALL (~0U)
    1722             : 
    1723             : gpg_error_t
    1724           0 : gt_result (gpgme_tool_t gt, unsigned int flags)
    1725             : {
    1726           0 :   int indent = 2;
    1727             : 
    1728           0 :   gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
    1729           0 :   gt_write_data (gt, NULL, 0);
    1730           0 :   gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
    1731           0 :   gt_write_data (gt, NULL, 0);
    1732           0 :   if (flags & GT_RESULT_ENCRYPT)
    1733           0 :     result_encrypt_to_xml (gt->ctx, indent,
    1734             :                            (result_xml_write_cb_t) gt_write_data, gt);
    1735           0 :   if (flags & GT_RESULT_DECRYPT)
    1736           0 :     result_decrypt_to_xml (gt->ctx, indent,
    1737             :                            (result_xml_write_cb_t) gt_write_data, gt);
    1738           0 :   if (flags & GT_RESULT_SIGN)
    1739           0 :     result_sign_to_xml (gt->ctx, indent,
    1740             :                         (result_xml_write_cb_t) gt_write_data, gt);
    1741           0 :   if (flags & GT_RESULT_VERIFY)
    1742           0 :     result_verify_to_xml (gt->ctx, indent,
    1743             :                           (result_xml_write_cb_t) gt_write_data, gt);
    1744           0 :   if (flags & GT_RESULT_IMPORT)
    1745           0 :     result_import_to_xml (gt->ctx, indent,
    1746             :                           (result_xml_write_cb_t) gt_write_data, gt);
    1747           0 :   if (flags & GT_RESULT_GENKEY)
    1748           0 :     result_genkey_to_xml (gt->ctx, indent,
    1749             :                           (result_xml_write_cb_t) gt_write_data, gt);
    1750           0 :   if (flags & GT_RESULT_KEYLIST)
    1751           0 :     result_keylist_to_xml (gt->ctx, indent,
    1752             :                            (result_xml_write_cb_t) gt_write_data, gt);
    1753           0 :   if (flags & GT_RESULT_VFS_MOUNT)
    1754           0 :     result_vfs_mount_to_xml (gt->ctx, indent,
    1755             :                              (result_xml_write_cb_t) gt_write_data, gt);
    1756           0 :   gt_write_data (gt, xml_end, strlen (xml_end));
    1757             : 
    1758           0 :   return 0;
    1759             : }
    1760             : 
    1761             : 
    1762             : /* GPGME SERVER.  */
    1763             : 
    1764             : #include <assuan.h>
    1765             : 
    1766             : struct server
    1767             : {
    1768             :   gpgme_tool_t gt;
    1769             :   assuan_context_t assuan_ctx;
    1770             : 
    1771             :   gpgme_data_encoding_t input_enc;
    1772             :   gpgme_data_encoding_t output_enc;
    1773             :   assuan_fd_t input_fd;
    1774             :   char *input_filename;
    1775             :   FILE *input_stream;
    1776             :   assuan_fd_t output_fd;
    1777             :   char *output_filename;
    1778             :   FILE *output_stream;
    1779             :   assuan_fd_t message_fd;
    1780             :   char *message_filename;
    1781             :   FILE *message_stream;
    1782             :   gpgme_data_encoding_t message_enc;
    1783             : };
    1784             : 
    1785             : 
    1786             : gpg_error_t
    1787           0 : server_write_status (void *hook, const char *status, const char *msg)
    1788             : {
    1789           0 :   struct server *server = hook;
    1790           0 :   return assuan_write_status (server->assuan_ctx, status, msg);
    1791             : }
    1792             : 
    1793             : 
    1794             : gpg_error_t
    1795           0 : server_write_data (void *hook, const void *buf, size_t len)
    1796             : {
    1797           0 :   struct server *server = hook;
    1798           0 :   return assuan_send_data (server->assuan_ctx, buf, len);
    1799             : }
    1800             : 
    1801             : 
    1802             : static gpg_error_t
    1803           0 : server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
    1804             :                       int was_bad, int fd)
    1805             : {
    1806           0 :   struct server *server = opaque;
    1807             :   gpg_error_t err;
    1808           0 :   unsigned char *buf = NULL;
    1809           0 :   size_t buflen = 0;
    1810             : 
    1811           0 :   if (server && server->assuan_ctx)
    1812             :     {
    1813           0 :       if (uid_hint)
    1814           0 :         assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
    1815           0 :       if (info)
    1816           0 :         assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
    1817             : 
    1818           0 :       err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
    1819             :                             &buf, &buflen, 100);
    1820             :     }
    1821             :   else
    1822           0 :     err = gpg_error (GPG_ERR_NO_PASSPHRASE);
    1823             : 
    1824           0 :   if (!err)
    1825             :     {
    1826             :       /* We take care to always send a LF.  */
    1827           0 :       if (gpgme_io_writen (fd, buf, buflen))
    1828           0 :         err = gpg_error_from_syserror ();
    1829           0 :       else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
    1830           0 :         err = gpg_error_from_syserror ();
    1831             :     }
    1832           0 :   free (buf);
    1833           0 :   return err;
    1834             : }
    1835             : 
    1836             : 
    1837             : /* Wrapper around assuan_command_parse_fd to also handle a
    1838             :    "file=FILENAME" argument.  On success either a filename is returned
    1839             :    at FILENAME or a file descriptor at RFD; the other one is set to
    1840             :    NULL respective ASSUAN_INVALID_FD.  */
    1841             : static gpg_error_t
    1842           0 : server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
    1843             :                  char **filename)
    1844             : {
    1845           0 :   *rfd = ASSUAN_INVALID_FD;
    1846           0 :   *filename = NULL;
    1847             : 
    1848           0 :   if (! strncasecmp (line, "file=", 5))
    1849             :     {
    1850             :       char *term;
    1851           0 :       *filename = strdup (line + 5);
    1852           0 :       if (!*filename)
    1853           0 :         return gpg_error_from_syserror();
    1854           0 :       term = strchr (*filename, ' ');
    1855           0 :       if (term)
    1856           0 :         *term = '\0';
    1857           0 :       return 0;
    1858             :     }
    1859             :   else
    1860           0 :     return assuan_command_parse_fd (ctx, line, rfd);
    1861             : }
    1862             : 
    1863             : 
    1864             : static gpgme_data_encoding_t
    1865           0 : server_data_encoding (const char *line)
    1866             : {
    1867           0 :   if (strstr (line, "--binary"))
    1868           0 :     return GPGME_DATA_ENCODING_BINARY;
    1869           0 :   if (strstr (line, "--base64"))
    1870           0 :     return GPGME_DATA_ENCODING_BASE64;
    1871           0 :   if (strstr (line, "--armor"))
    1872           0 :     return GPGME_DATA_ENCODING_ARMOR;
    1873           0 :   if (strstr (line, "--url"))
    1874           0 :     return GPGME_DATA_ENCODING_URL;
    1875           0 :   if (strstr (line, "--urlesc"))
    1876           0 :     return GPGME_DATA_ENCODING_URLESC;
    1877           0 :   if (strstr (line, "--url0"))
    1878           0 :     return GPGME_DATA_ENCODING_URL0;
    1879           0 :   if (strstr (line, "--mime"))
    1880           0 :     return GPGME_DATA_ENCODING_MIME;
    1881           0 :   return GPGME_DATA_ENCODING_NONE;
    1882             : }
    1883             : 
    1884             : 
    1885             : static gpgme_error_t
    1886           0 : server_data_obj (assuan_fd_t fd, char *fn, int out,
    1887             :                  gpgme_data_encoding_t encoding,
    1888             :                  gpgme_data_t *data, FILE **fs)
    1889             : {
    1890             :   gpgme_error_t err;
    1891             : 
    1892           0 :   *fs = NULL;
    1893           0 :   if (fn)
    1894             :     {
    1895           0 :       *fs = fopen (fn, out ? "wb" : "rb");
    1896           0 :       if (!*fs)
    1897           0 :         return gpg_error_from_syserror ();
    1898             : 
    1899           0 :       err = gpgme_data_new_from_stream (data, *fs);
    1900             :     }
    1901             :   else
    1902           0 :     err = gpgme_data_new_from_fd (data, (int) fd);
    1903             : 
    1904           0 :   if (err)
    1905           0 :     return err;
    1906           0 :   return gpgme_data_set_encoding (*data, encoding);
    1907             : }
    1908             : 
    1909             : 
    1910             : void
    1911           0 : server_reset_fds (struct server *server)
    1912             : {
    1913             :   /* assuan closes the input and output FDs for us when doing a RESET,
    1914             :      but we use this same function after commands, so repeat it
    1915             :      here.  */
    1916           0 :   if (server->input_fd != ASSUAN_INVALID_FD)
    1917             :     {
    1918             : #if HAVE_W32_SYSTEM
    1919             :       CloseHandle (server->input_fd);
    1920             : #else
    1921           0 :       close (server->input_fd);
    1922             : #endif
    1923           0 :       server->input_fd = ASSUAN_INVALID_FD;
    1924             :     }
    1925           0 :   if (server->output_fd != ASSUAN_INVALID_FD)
    1926             :     {
    1927             : #if HAVE_W32_SYSTEM
    1928             :       CloseHandle (server->output_fd);
    1929             : #else
    1930           0 :       close (server->output_fd);
    1931             : #endif
    1932           0 :       server->output_fd = ASSUAN_INVALID_FD;
    1933             :     }
    1934           0 :   if (server->message_fd != ASSUAN_INVALID_FD)
    1935             :     {
    1936             :       /* FIXME: Assuan should provide a close function.  */
    1937             : #if HAVE_W32_SYSTEM
    1938             :       CloseHandle (server->message_fd);
    1939             : #else
    1940           0 :       close (server->message_fd);
    1941             : #endif
    1942           0 :       server->message_fd = ASSUAN_INVALID_FD;
    1943             :     }
    1944           0 :   if (server->input_filename)
    1945             :     {
    1946           0 :       free (server->input_filename);
    1947           0 :       server->input_filename = NULL;
    1948             :     }
    1949           0 :   if (server->output_filename)
    1950             :     {
    1951           0 :       free (server->output_filename);
    1952           0 :       server->output_filename = NULL;
    1953             :     }
    1954           0 :   if (server->message_filename)
    1955             :     {
    1956           0 :       free (server->message_filename);
    1957           0 :       server->message_filename = NULL;
    1958             :     }
    1959           0 :   if (server->input_stream)
    1960             :     {
    1961           0 :       fclose (server->input_stream);
    1962           0 :       server->input_stream = NULL;
    1963             :     }
    1964           0 :   if (server->output_stream)
    1965             :     {
    1966           0 :       fclose (server->output_stream);
    1967           0 :       server->output_stream = NULL;
    1968             :     }
    1969           0 :   if (server->message_stream)
    1970             :     {
    1971           0 :       fclose (server->message_stream);
    1972           0 :       server->message_stream = NULL;
    1973             :     }
    1974             : 
    1975           0 :   server->input_enc = GPGME_DATA_ENCODING_NONE;
    1976           0 :   server->output_enc = GPGME_DATA_ENCODING_NONE;
    1977           0 :   server->message_enc = GPGME_DATA_ENCODING_NONE;
    1978           0 : }
    1979             : 
    1980             : 
    1981             : static gpg_error_t
    1982           0 : reset_notify (assuan_context_t ctx, char *line)
    1983             : {
    1984           0 :   struct server *server = assuan_get_pointer (ctx);
    1985           0 :   server_reset_fds (server);
    1986           0 :   gt_reset (server->gt);
    1987           0 :   return 0;
    1988             : }
    1989             : 
    1990             : 
    1991             : static const char hlp_version[] =
    1992             :   "VERSION [<string>]\n"
    1993             :   "\n"
    1994             :   "Call the function gpgme_check_version.";
    1995             : static gpg_error_t
    1996           0 : cmd_version (assuan_context_t ctx, char *line)
    1997             : {
    1998           0 :   if (line && *line)
    1999             :     {
    2000           0 :       const char *version = gpgme_check_version (line);
    2001           0 :       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
    2002             :     }
    2003             :   else
    2004             :     {
    2005           0 :       const char *version = gpgme_check_version (NULL);
    2006           0 :       return assuan_send_data (ctx, version, strlen (version));
    2007             :     }
    2008             : }
    2009             : 
    2010             : 
    2011             : static const char hlp_engine[] =
    2012             :   "ENGINE [<string>]\n"
    2013             :   "\n"
    2014             :   "Get information about a GPGME engine (a.k.a. protocol).";
    2015             : static gpg_error_t
    2016           0 : cmd_engine (assuan_context_t ctx, char *line)
    2017             : {
    2018           0 :   struct server *server = assuan_get_pointer (ctx);
    2019           0 :   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
    2020             : }
    2021             : 
    2022             : 
    2023             : static const char hlp_protocol[] =
    2024             :   "PROTOCOL [<name>]\n"
    2025             :   "\n"
    2026             :   "With NAME, set the protocol.  Without, return the current\n"
    2027             :   "protocol.";
    2028             : static gpg_error_t
    2029           0 : cmd_protocol (assuan_context_t ctx, char *line)
    2030             : {
    2031           0 :   struct server *server = assuan_get_pointer (ctx);
    2032           0 :   if (line && *line)
    2033           0 :     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
    2034             :   else
    2035           0 :     return gt_get_protocol (server->gt);
    2036             : }
    2037             : 
    2038             : 
    2039             : static const char hlp_sub_protocol[] =
    2040             :   "SUB_PROTOCOL [<name>]\n"
    2041             :   "\n"
    2042             :   "With NAME, set the sub-protocol.  Without, return the\n"
    2043             :   "current sub-protocol.";
    2044             : static gpg_error_t
    2045           0 : cmd_sub_protocol (assuan_context_t ctx, char *line)
    2046             : {
    2047           0 :   struct server *server = assuan_get_pointer (ctx);
    2048           0 :   if (line && *line)
    2049           0 :     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
    2050             :   else
    2051           0 :     return gt_get_sub_protocol (server->gt);
    2052             : }
    2053             : 
    2054             : 
    2055             : static const char hlp_pinentry_mode[] =
    2056             :   "PINENTRY_MODE <name>\n"
    2057             :   "\n"
    2058             :   "Set the pinentry mode to NAME.   Allowedvalues for NAME are:\n"
    2059             :   "  default  - reset to the default of the engine,\n"
    2060             :   "  ask      - force the use of the pinentry,\n"
    2061             :   "  cancel   - emulate use of pinentry's cancel button,\n"
    2062             :   "  error    - return a pinentry error,\n"
    2063             :   "  loopback - redirect pinentry queries to the caller.\n"
    2064             :   "Note that only recent versions of GPG support changing the pinentry mode.";
    2065             : static gpg_error_t
    2066           0 : cmd_pinentry_mode (assuan_context_t ctx, char *line)
    2067             : {
    2068           0 :   struct server *server = assuan_get_pointer (ctx);
    2069             :   gpgme_pinentry_mode_t mode;
    2070             : 
    2071           0 :   if (!line || !*line || !strcmp (line, "default"))
    2072           0 :     mode = GPGME_PINENTRY_MODE_DEFAULT;
    2073           0 :   else if (!strcmp (line, "ask"))
    2074           0 :     mode = GPGME_PINENTRY_MODE_ASK;
    2075           0 :   else if (!strcmp (line, "cancel"))
    2076           0 :     mode = GPGME_PINENTRY_MODE_CANCEL;
    2077           0 :   else if (!strcmp (line, "error"))
    2078           0 :     mode = GPGME_PINENTRY_MODE_ERROR;
    2079           0 :   else if (!strcmp (line, "loopback"))
    2080           0 :     mode = GPGME_PINENTRY_MODE_LOOPBACK;
    2081             :   else
    2082           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    2083             : 
    2084           0 :   return gt_set_pinentry_mode (server->gt, mode, server);
    2085             : }
    2086             : 
    2087             : 
    2088             : static const char hlp_armor[] =
    2089             :   "ARMOR [true|false]\n"
    2090             :   "\n"
    2091             :   "With 'true' or 'false', turn output ASCII armoring on or\n"
    2092             :   "off.  Without, return the current armoring status.";
    2093             : static gpg_error_t
    2094           0 : cmd_armor (assuan_context_t ctx, char *line)
    2095             : {
    2096           0 :   struct server *server = assuan_get_pointer (ctx);
    2097           0 :   if (line && *line)
    2098             :     {
    2099           0 :       int flag = 0;
    2100             : 
    2101           0 :       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
    2102           0 :           || line[0] == '1')
    2103           0 :         flag = 1;
    2104             : 
    2105           0 :       return gt_set_armor (server->gt, flag);
    2106             :     }
    2107             :   else
    2108           0 :     return gt_get_armor (server->gt);
    2109             : }
    2110             : 
    2111             : 
    2112             : static const char hlp_textmode[] =
    2113             :   "TEXTMODE [true|false]\n"
    2114             :   "\n"
    2115             :   "With 'true' or 'false', turn text mode on or off.\n"
    2116             :   "Without, return the current text mode status.";
    2117             : static gpg_error_t
    2118           0 : cmd_textmode (assuan_context_t ctx, char *line)
    2119             : {
    2120           0 :   struct server *server = assuan_get_pointer (ctx);
    2121           0 :   if (line && *line)
    2122             :     {
    2123           0 :       int flag = 0;
    2124             : 
    2125           0 :       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
    2126           0 :           || line[0] == '1')
    2127           0 :         flag = 1;
    2128             : 
    2129           0 :       return gt_set_textmode (server->gt, flag);
    2130             :     }
    2131             :   else
    2132           0 :     return gt_get_textmode (server->gt);
    2133             : }
    2134             : 
    2135             : 
    2136             : static const char hlp_include_certs[] =
    2137             :   "INCLUDE_CERTS [default|<n>]\n"
    2138             :   "\n"
    2139             :   "With DEFAULT or N, set how many certificates should be\n"
    2140             :   "included in the next S/MIME signed message.  See the\n"
    2141             :   "GPGME documentation for details on the meaning of"
    2142             :   "various N.  Without either, return the current setting.";
    2143             : static gpg_error_t
    2144           0 : cmd_include_certs (assuan_context_t ctx, char *line)
    2145             : {
    2146           0 :   struct server *server = assuan_get_pointer (ctx);
    2147             : 
    2148           0 :   if (line && *line)
    2149             :     {
    2150           0 :       int include_certs = 0;
    2151             : 
    2152           0 :       if (! strcasecmp (line, "default"))
    2153           0 :         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
    2154             :       else
    2155           0 :         include_certs = atoi (line);
    2156             : 
    2157           0 :       return gt_set_include_certs (server->gt, include_certs);
    2158             :     }
    2159             :   else
    2160           0 :     return gt_get_include_certs (server->gt);
    2161             : }
    2162             : 
    2163             : 
    2164             : static const char hlp_keylist_mode[] =
    2165             :   "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
    2166             :   "  [ephemeral] [validate]\n"
    2167             :   "\n"
    2168             :   "Set the mode for the next KEYLIST command.";
    2169             : static gpg_error_t
    2170           0 : cmd_keylist_mode (assuan_context_t ctx, char *line)
    2171             : {
    2172           0 :   struct server *server = assuan_get_pointer (ctx);
    2173             : 
    2174           0 :   if (line && *line)
    2175             :     {
    2176           0 :       gpgme_keylist_mode_t mode = 0;
    2177             : 
    2178           0 :       if (strstr (line, "local"))
    2179           0 :         mode |= GPGME_KEYLIST_MODE_LOCAL;
    2180           0 :       if (strstr (line, "extern"))
    2181           0 :         mode |= GPGME_KEYLIST_MODE_EXTERN;
    2182           0 :       if (strstr (line, "sigs"))
    2183           0 :         mode |= GPGME_KEYLIST_MODE_SIGS;
    2184           0 :       if (strstr (line, "sig_notations"))
    2185           0 :         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
    2186           0 :       if (strstr (line, "with_secret"))
    2187           0 :         mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
    2188           0 :       if (strstr (line, "ephemeral"))
    2189           0 :         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
    2190           0 :       if (strstr (line, "validate"))
    2191           0 :         mode |= GPGME_KEYLIST_MODE_VALIDATE;
    2192             : 
    2193           0 :       return gt_set_keylist_mode (server->gt, mode);
    2194             :     }
    2195             :   else
    2196           0 :     return gt_get_keylist_mode (server->gt);
    2197             : }
    2198             : 
    2199             : 
    2200             : static const char hlp_input[] =
    2201             :   "INPUT [<fd>|FILE=<path>]\n"
    2202             :   "\n"
    2203             :   "Set the input for the next command.  Use either the\n"
    2204             :   "Assuan file descriptor FD or a filesystem PATH.";
    2205             : static gpg_error_t
    2206           0 : cmd_input (assuan_context_t ctx, char *line)
    2207             : {
    2208           0 :   struct server *server = assuan_get_pointer (ctx);
    2209             :   gpg_error_t err;
    2210             :   assuan_fd_t sysfd;
    2211             :   char *filename;
    2212             : 
    2213           0 :   err = server_parse_fd (ctx, line, &sysfd, &filename);
    2214           0 :   if (err)
    2215           0 :     return err;
    2216           0 :   server->input_fd = sysfd;
    2217           0 :   server->input_filename = filename;
    2218           0 :   server->input_enc = server_data_encoding (line);
    2219           0 :   return 0;
    2220             : }
    2221             : 
    2222             : 
    2223             : static const char hlp_output[] =
    2224             :   "OUTPUT [<fd>|FILE=<path>]\n"
    2225             :   "\n"
    2226             :   "Set the output for the next command.  Use either the\n"
    2227             :   "Assuan file descriptor FD or a filesystem PATH.";
    2228             : static gpg_error_t
    2229           0 : cmd_output (assuan_context_t ctx, char *line)
    2230             : {
    2231           0 :   struct server *server = assuan_get_pointer (ctx);
    2232             :   gpg_error_t err;
    2233             :   assuan_fd_t sysfd;
    2234             :   char *filename;
    2235             : 
    2236           0 :   err = server_parse_fd (ctx, line, &sysfd, &filename);
    2237           0 :   if (err)
    2238           0 :     return err;
    2239           0 :   server->output_fd = sysfd;
    2240           0 :   server->output_filename = filename;
    2241           0 :   server->output_enc = server_data_encoding (line);
    2242           0 :   return 0;
    2243             : }
    2244             : 
    2245             : 
    2246             : static const char hlp_message[] =
    2247             :   "MESSAGE [<fd>|FILE=<path>]\n"
    2248             :   "\n"
    2249             :   "Set the plaintext message for the next VERIFY command\n"
    2250             :   "with a detached signature.  Use either the Assuan file\n"
    2251             :   "descriptor FD or a filesystem PATH.";
    2252             : static gpg_error_t
    2253           0 : cmd_message (assuan_context_t ctx, char *line)
    2254             : {
    2255           0 :   struct server *server = assuan_get_pointer (ctx);
    2256             :   gpg_error_t err;
    2257             :   assuan_fd_t sysfd;
    2258             :   char *filename;
    2259             : 
    2260           0 :   err = server_parse_fd (ctx, line, &sysfd, &filename);
    2261           0 :   if (err)
    2262           0 :     return err;
    2263           0 :   server->message_fd = sysfd;
    2264           0 :   server->message_filename = filename;
    2265           0 :   server->message_enc = server_data_encoding (line);
    2266           0 :   return 0;
    2267             : }
    2268             : 
    2269             : 
    2270             : static const char hlp_recipient[] =
    2271             :   "RECIPIENT <pattern>\n"
    2272             :   "\n"
    2273             :   "Add the key matching PATTERN to the list of recipients\n"
    2274             :   "for the next encryption command.";
    2275             : static gpg_error_t
    2276           0 : cmd_recipient (assuan_context_t ctx, char *line)
    2277             : {
    2278           0 :   struct server *server = assuan_get_pointer (ctx);
    2279             : 
    2280           0 :   return gt_recipients_add (server->gt, line);
    2281             : }
    2282             : 
    2283             : 
    2284             : static const char hlp_signer[] =
    2285             :   "SIGNER <fingerprint>\n"
    2286             :   "\n"
    2287             :   "Add the key with FINGERPRINT to the list of signers to\n"
    2288             :   "be used for the next signing command.";
    2289             : static gpg_error_t
    2290           0 : cmd_signer (assuan_context_t ctx, char *line)
    2291             : {
    2292           0 :   struct server *server = assuan_get_pointer (ctx);
    2293             : 
    2294           0 :   return gt_signers_add (server->gt, line);
    2295             : }
    2296             : 
    2297             : 
    2298             : static const char hlp_signers_clear[] =
    2299             :   "SIGNERS_CLEAR\n"
    2300             :   "\n"
    2301             :   "Clear the list of signers specified by previous SIGNER\n"
    2302             :   "commands.";
    2303             : static gpg_error_t
    2304           0 : cmd_signers_clear (assuan_context_t ctx, char *line)
    2305             : {
    2306           0 :   struct server *server = assuan_get_pointer (ctx);
    2307             : 
    2308           0 :   return gt_signers_clear (server->gt);
    2309             : }
    2310             : 
    2311             : 
    2312             : static gpg_error_t
    2313           0 : _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
    2314             : {
    2315           0 :   struct server *server = assuan_get_pointer (ctx);
    2316             :   gpg_error_t err;
    2317             :   assuan_fd_t inp_fd;
    2318             :   char *inp_fn;
    2319             :   assuan_fd_t out_fd;
    2320             :   char *out_fn;
    2321             :   gpgme_data_t inp_data;
    2322             :   gpgme_data_t out_data;
    2323             : 
    2324           0 :   inp_fd = server->input_fd;
    2325           0 :   inp_fn = server->input_filename;
    2326           0 :   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
    2327           0 :     return GPG_ERR_ASS_NO_INPUT;
    2328           0 :   out_fd = server->output_fd;
    2329           0 :   out_fn = server->output_filename;
    2330           0 :   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
    2331           0 :     return GPG_ERR_ASS_NO_OUTPUT;
    2332             : 
    2333           0 :   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    2334             :                          &server->input_stream);
    2335           0 :   if (err)
    2336           0 :     return err;
    2337           0 :   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2338             :                          &server->output_stream);
    2339           0 :   if (err)
    2340             :     {
    2341           0 :       gpgme_data_release (inp_data);
    2342           0 :       return err;
    2343             :     }
    2344             : 
    2345           0 :   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
    2346             : 
    2347           0 :   gpgme_data_release (inp_data);
    2348           0 :   gpgme_data_release (out_data);
    2349             : 
    2350           0 :   server_reset_fds (server);
    2351             : 
    2352           0 :   return err;
    2353             : }
    2354             : 
    2355             : 
    2356             : static const char hlp_decrypt[] =
    2357             :   "DECRYPT\n"
    2358             :   "\n"
    2359             :   "Decrypt the object set by the last INPUT command and\n"
    2360             :   "write the decrypted message to the object set by the\n"
    2361             :   "last OUTPUT command.";
    2362             : static gpg_error_t
    2363           0 : cmd_decrypt (assuan_context_t ctx, char *line)
    2364             : {
    2365           0 :   return _cmd_decrypt_verify (ctx, line, 0);
    2366             : }
    2367             : 
    2368             : 
    2369             : static const char hlp_decrypt_verify[] =
    2370             :   "DECRYPT_VERIFY\n"
    2371             :   "\n"
    2372             :   "Decrypt the object set by the last INPUT command and\n"
    2373             :   "verify any embedded signatures.  Write the decrypted\n"
    2374             :   "message to the object set by the last OUTPUT command.";
    2375             : static gpg_error_t
    2376           0 : cmd_decrypt_verify (assuan_context_t ctx, char *line)
    2377             : {
    2378           0 :   return _cmd_decrypt_verify (ctx, line, 1);
    2379             : }
    2380             : 
    2381             : 
    2382             : static gpg_error_t
    2383           0 : _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
    2384             : {
    2385           0 :   struct server *server = assuan_get_pointer (ctx);
    2386             :   gpg_error_t err;
    2387             :   assuan_fd_t inp_fd;
    2388             :   char *inp_fn;
    2389             :   assuan_fd_t out_fd;
    2390             :   char *out_fn;
    2391           0 :   gpgme_data_t inp_data = NULL;
    2392           0 :   gpgme_data_t out_data = NULL;
    2393           0 :   gpgme_encrypt_flags_t flags = 0;
    2394             : 
    2395           0 :   if (strstr (line, "--always-trust"))
    2396           0 :     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
    2397           0 :   if (strstr (line, "--no-encrypt-to"))
    2398           0 :     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
    2399           0 :   if (strstr (line, "--prepare"))
    2400           0 :     flags |= GPGME_ENCRYPT_PREPARE;
    2401           0 :   if (strstr (line, "--expect-sign"))
    2402           0 :     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
    2403           0 :   if (strstr (line, "--no-compress"))
    2404           0 :     flags |= GPGME_ENCRYPT_NO_COMPRESS;
    2405             : 
    2406           0 :   inp_fd = server->input_fd;
    2407           0 :   inp_fn = server->input_filename;
    2408           0 :   out_fd = server->output_fd;
    2409           0 :   out_fn = server->output_filename;
    2410           0 :   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
    2411             :     {
    2412           0 :       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    2413             :                              &server->input_stream);
    2414           0 :       if (err)
    2415           0 :         return err;
    2416             :     }
    2417           0 :   if (out_fd != ASSUAN_INVALID_FD || out_fn)
    2418             :     {
    2419           0 :       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2420             :                              &server->output_stream);
    2421           0 :       if (err)
    2422             :         {
    2423           0 :           gpgme_data_release (inp_data);
    2424           0 :           return err;
    2425             :         }
    2426             :     }
    2427             : 
    2428           0 :   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
    2429             : 
    2430           0 :   gpgme_data_release (inp_data);
    2431           0 :   gpgme_data_release (out_data);
    2432             : 
    2433           0 :   server_reset_fds (server);
    2434             : 
    2435           0 :   return err;
    2436             : }
    2437             : 
    2438             : 
    2439             : static const char hlp_encrypt[] =
    2440             :   "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
    2441             :   "  [--no-compress] [--prepare] [--expect-sign]\n"
    2442             :   "\n"
    2443             :   "Encrypt the object set by the last INPUT command to\n"
    2444             :   "the keys specified by previous RECIPIENT commands.  \n"
    2445             :   "Write the signed and encrypted message to the object\n"
    2446             :   "set by the last OUTPUT command.";
    2447             : static gpg_error_t
    2448           0 : cmd_encrypt (assuan_context_t ctx, char *line)
    2449             : {
    2450           0 :   return _cmd_sign_encrypt (ctx, line, 0);
    2451             : }
    2452             : 
    2453             : 
    2454             : static const char hlp_sign_encrypt[] =
    2455             :   "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
    2456             :   "  [--no-compress] [--prepare] [--expect-sign]\n"
    2457             :   "\n"
    2458             :   "Sign the object set by the last INPUT command with the\n"
    2459             :   "keys specified by previous SIGNER commands and encrypt\n"
    2460             :   "it to the keys specified by previous RECIPIENT\n"
    2461             :   "commands.  Write the signed and encrypted message to\n"
    2462             :   "the object set by the last OUTPUT command.";
    2463             : static gpg_error_t
    2464           0 : cmd_sign_encrypt (assuan_context_t ctx, char *line)
    2465             : {
    2466           0 :   return _cmd_sign_encrypt (ctx, line, 1);
    2467             : }
    2468             : 
    2469             : 
    2470             : static const char hlp_sign[] =
    2471             :   "SIGN [--clear|--detach]\n"
    2472             :   "\n"
    2473             :   "Sign the object set by the last INPUT command with the\n"
    2474             :   "keys specified by previous SIGNER commands.  Write the\n"
    2475             :   "signed message to the object set by the last OUTPUT\n"
    2476             :   "command.  With `--clear`, generate a clear text\n"
    2477             :   "signature.  With `--detach`, generate a detached\n"
    2478             :   "signature.";
    2479             : static gpg_error_t
    2480           0 : cmd_sign (assuan_context_t ctx, char *line)
    2481             : {
    2482           0 :   struct server *server = assuan_get_pointer (ctx);
    2483             :   gpg_error_t err;
    2484             :   assuan_fd_t inp_fd;
    2485             :   char *inp_fn;
    2486             :   assuan_fd_t out_fd;
    2487             :   char *out_fn;
    2488             :   gpgme_data_t inp_data;
    2489             :   gpgme_data_t out_data;
    2490           0 :   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
    2491             : 
    2492           0 :   if (strstr (line, "--clear"))
    2493           0 :     mode = GPGME_SIG_MODE_CLEAR;
    2494           0 :   if (strstr (line, "--detach"))
    2495           0 :     mode = GPGME_SIG_MODE_DETACH;
    2496             : 
    2497           0 :   inp_fd = server->input_fd;
    2498           0 :   inp_fn = server->input_filename;
    2499           0 :   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
    2500           0 :     return GPG_ERR_ASS_NO_INPUT;
    2501           0 :   out_fd = server->output_fd;
    2502           0 :   out_fn = server->output_filename;
    2503           0 :   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
    2504           0 :     return GPG_ERR_ASS_NO_OUTPUT;
    2505             : 
    2506           0 :   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    2507             :                          &server->input_stream);
    2508           0 :   if (err)
    2509           0 :     return err;
    2510           0 :   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2511             :                          &server->output_stream);
    2512           0 :   if (err)
    2513             :     {
    2514           0 :       gpgme_data_release (inp_data);
    2515           0 :       return err;
    2516             :     }
    2517             : 
    2518           0 :   err = gt_sign (server->gt, inp_data, out_data, mode);
    2519             : 
    2520           0 :   gpgme_data_release (inp_data);
    2521           0 :   gpgme_data_release (out_data);
    2522           0 :   server_reset_fds (server);
    2523             : 
    2524           0 :   return err;
    2525             : }
    2526             : 
    2527             : 
    2528             : static const char hlp_verify[] =
    2529             :   "VERIFY\n"
    2530             :   "\n"
    2531             :   "Verify signatures on the object set by the last INPUT\n"
    2532             :   "and MESSAGE commands.  If the message was encrypted,\n"
    2533             :   "write the plaintext to the object set by the last\n"
    2534             :   "OUTPUT command.";
    2535             : static gpg_error_t
    2536           0 : cmd_verify (assuan_context_t ctx, char *line)
    2537             : {
    2538           0 :   struct server *server = assuan_get_pointer (ctx);
    2539             :   gpg_error_t err;
    2540             :   assuan_fd_t inp_fd;
    2541             :   assuan_fd_t msg_fd;
    2542             :   assuan_fd_t out_fd;
    2543             :   char *inp_fn;
    2544             :   char *msg_fn;
    2545             :   char *out_fn;
    2546             :   gpgme_data_t inp_data;
    2547           0 :   gpgme_data_t msg_data = NULL;
    2548           0 :   gpgme_data_t out_data = NULL;
    2549             : 
    2550           0 :   inp_fd = server->input_fd;
    2551           0 :   inp_fn = server->input_filename;
    2552           0 :   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
    2553           0 :     return GPG_ERR_ASS_NO_INPUT;
    2554           0 :   msg_fd = server->message_fd;
    2555           0 :   msg_fn = server->message_filename;
    2556           0 :   out_fd = server->output_fd;
    2557           0 :   out_fn = server->output_filename;
    2558             : 
    2559           0 :   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    2560             :                          &server->input_stream);
    2561           0 :   if (err)
    2562           0 :     return err;
    2563           0 :   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
    2564             :     {
    2565           0 :       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
    2566             :                              &server->message_stream);
    2567           0 :       if (err)
    2568             :         {
    2569           0 :           gpgme_data_release (inp_data);
    2570           0 :           return err;
    2571             :         }
    2572             :     }
    2573           0 :   if (out_fd != ASSUAN_INVALID_FD || out_fn)
    2574             :     {
    2575           0 :       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2576             :                              &server->output_stream);
    2577           0 :       if (err)
    2578             :         {
    2579           0 :           gpgme_data_release (inp_data);
    2580           0 :           gpgme_data_release (msg_data);
    2581           0 :           return err;
    2582             :         }
    2583             :     }
    2584             : 
    2585           0 :   err = gt_verify (server->gt, inp_data, msg_data, out_data);
    2586             : 
    2587           0 :   gpgme_data_release (inp_data);
    2588           0 :   if (msg_data)
    2589           0 :     gpgme_data_release (msg_data);
    2590           0 :   if (out_data)
    2591           0 :     gpgme_data_release (out_data);
    2592             : 
    2593           0 :   server_reset_fds (server);
    2594             : 
    2595           0 :   return err;
    2596             : }
    2597             : 
    2598             : 
    2599             : static const char hlp_import[] =
    2600             :   "IMPORT [<pattern>]\n"
    2601             :   "\n"
    2602             :   "With PATTERN, import the keys described by PATTERN.\n"
    2603             :   "Without, read a key (or keys) from the object set by the\n"
    2604             :   "last INPUT command.";
    2605             : static gpg_error_t
    2606           0 : cmd_import (assuan_context_t ctx, char *line)
    2607             : {
    2608           0 :   struct server *server = assuan_get_pointer (ctx);
    2609             : 
    2610           0 :   if (line && *line)
    2611             :     {
    2612           0 :       char *fprs[2] = { line, NULL };
    2613             : 
    2614           0 :       return gt_import_keys (server->gt, fprs);
    2615             :     }
    2616             :   else
    2617             :     {
    2618             :       gpg_error_t err;
    2619             :       assuan_fd_t inp_fd;
    2620             :       char *inp_fn;
    2621             :       gpgme_data_t inp_data;
    2622             : 
    2623           0 :       inp_fd = server->input_fd;
    2624           0 :       inp_fn = server->input_filename;
    2625           0 :       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
    2626           0 :         return GPG_ERR_ASS_NO_INPUT;
    2627             : 
    2628           0 :       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    2629             :                              &server->input_stream);
    2630           0 :       if (err)
    2631           0 :         return err;
    2632             : 
    2633           0 :       err = gt_import (server->gt, inp_data);
    2634             : 
    2635           0 :       gpgme_data_release (inp_data);
    2636           0 :       server_reset_fds (server);
    2637             : 
    2638           0 :       return err;
    2639             :     }
    2640             : }
    2641             : 
    2642             : 
    2643             : static const char hlp_export[] =
    2644             :   "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n"
    2645             :   "\n"
    2646             :   "Export the keys described by PATTERN.  Write the\n"
    2647             :   "the output to the object set by the last OUTPUT command.";
    2648             : static gpg_error_t
    2649           0 : cmd_export (assuan_context_t ctx, char *line)
    2650             : {
    2651           0 :   struct server *server = assuan_get_pointer (ctx);
    2652             :   gpg_error_t err;
    2653             :   assuan_fd_t out_fd;
    2654             :   char *out_fn;
    2655             :   gpgme_data_t out_data;
    2656           0 :   gpgme_export_mode_t mode = 0;
    2657             :   const char *pattern[2];
    2658             : 
    2659           0 :   out_fd = server->output_fd;
    2660           0 :   out_fn = server->output_filename;
    2661           0 :   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
    2662           0 :     return GPG_ERR_ASS_NO_OUTPUT;
    2663           0 :   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2664             :                          &server->output_stream);
    2665           0 :   if (err)
    2666           0 :     return err;
    2667             : 
    2668           0 :   if (has_option (line, "--extern"))
    2669           0 :     mode |= GPGME_EXPORT_MODE_EXTERN;
    2670           0 :   if (has_option (line, "--minimal"))
    2671           0 :     mode |= GPGME_EXPORT_MODE_MINIMAL;
    2672           0 :   if (has_option (line, "--secret"))
    2673           0 :     mode |= GPGME_EXPORT_MODE_SECRET;
    2674           0 :   if (has_option (line, "--raw"))
    2675           0 :     mode |= GPGME_EXPORT_MODE_RAW;
    2676           0 :   if (has_option (line, "--pkcs12"))
    2677           0 :     mode |= GPGME_EXPORT_MODE_PKCS12;
    2678             : 
    2679           0 :   line = skip_options (line);
    2680             : 
    2681           0 :   pattern[0] = line;
    2682           0 :   pattern[1] = NULL;
    2683             : 
    2684           0 :   err = gt_export (server->gt, pattern, mode, out_data);
    2685             : 
    2686           0 :   gpgme_data_release (out_data);
    2687           0 :   server_reset_fds (server);
    2688             : 
    2689           0 :   return err;
    2690             : }
    2691             : 
    2692             : 
    2693             : static gpg_error_t
    2694           0 : _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
    2695             : {
    2696           0 :   while (size > 0)
    2697             :     {
    2698           0 :       gpgme_ssize_t writen = gpgme_data_write (data, buf, size);
    2699           0 :       if (writen < 0 && errno != EAGAIN)
    2700           0 :         return gpg_error_from_syserror ();
    2701           0 :       else if (writen > 0)
    2702             :         {
    2703           0 :           buf = (void *) (((char *) buf) + writen);
    2704           0 :           size -= writen;
    2705             :         }
    2706             :     }
    2707           0 :   return 0;
    2708             : }
    2709             : 
    2710             : 
    2711             : static gpg_error_t
    2712           0 : cmd_genkey (assuan_context_t ctx, char *line)
    2713             : {
    2714           0 :   struct server *server = assuan_get_pointer (ctx);
    2715             :   gpg_error_t err;
    2716             :   assuan_fd_t inp_fd;
    2717             :   char *inp_fn;
    2718             :   assuan_fd_t out_fd;
    2719             :   char *out_fn;
    2720             :   gpgme_data_t inp_data;
    2721           0 :   gpgme_data_t out_data = NULL;
    2722           0 :   gpgme_data_t parms_data = NULL;
    2723             :   const char *parms;
    2724             : 
    2725           0 :   inp_fd = server->input_fd;
    2726           0 :   inp_fn = server->input_filename;
    2727           0 :   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
    2728           0 :     return GPG_ERR_ASS_NO_INPUT;
    2729           0 :   out_fd = server->output_fd;
    2730           0 :   out_fn = server->output_filename;
    2731             : 
    2732           0 :   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    2733             :                          &server->input_stream);
    2734           0 :   if (err)
    2735           0 :     return err;
    2736           0 :   if (out_fd != ASSUAN_INVALID_FD || out_fn)
    2737             :     {
    2738           0 :       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2739             :                              &server->output_stream);
    2740           0 :       if (err)
    2741             :         {
    2742           0 :           gpgme_data_release (inp_data);
    2743           0 :           return err;
    2744             :         }
    2745             :     }
    2746             : 
    2747             :   /* Convert input data.  */
    2748           0 :   err = gpgme_data_new (&parms_data);
    2749           0 :   if (err)
    2750           0 :     goto out;
    2751             :   do
    2752             :     {
    2753             :       char buf[512];
    2754           0 :       gpgme_ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
    2755           0 :       if (readn < 0)
    2756             :         {
    2757           0 :           err = gpg_error_from_syserror ();
    2758           0 :           goto out;
    2759             :         }
    2760           0 :       else if (readn == 0)
    2761           0 :         break;
    2762             : 
    2763           0 :       err = _cmd_genkey_write (parms_data, buf, readn);
    2764           0 :       if (err)
    2765           0 :         goto out;
    2766             :     }
    2767           0 :   while (1);
    2768           0 :   err = _cmd_genkey_write (parms_data, "", 1);
    2769           0 :   if (err)
    2770           0 :     goto out;
    2771           0 :   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
    2772           0 :   parms_data = NULL;
    2773           0 :   if (! parms)
    2774             :     {
    2775           0 :       err = gpg_error (GPG_ERR_GENERAL);
    2776           0 :       goto out;
    2777             :     }
    2778             : 
    2779           0 :   err = gt_genkey (server->gt, parms, out_data, NULL);
    2780             : 
    2781           0 :   server_reset_fds (server);
    2782             : 
    2783             :  out:
    2784           0 :   gpgme_data_release (inp_data);
    2785           0 :   if (out_data)
    2786           0 :     gpgme_data_release (out_data);
    2787           0 :   if (parms_data)
    2788           0 :     gpgme_data_release (parms_data);
    2789             : 
    2790           0 :   return err;
    2791             : }
    2792             : 
    2793             : 
    2794             : static gpg_error_t
    2795           0 : cmd_delete (assuan_context_t ctx, char *line)
    2796             : {
    2797           0 :   struct server *server = assuan_get_pointer (ctx);
    2798           0 :   int allow_secret = 0;
    2799           0 :   const char optstr[] = "--allow-secret";
    2800             : 
    2801           0 :   if (!strncasecmp (line, optstr, strlen (optstr)))
    2802             :     {
    2803           0 :       allow_secret = 1;
    2804           0 :       line += strlen (optstr);
    2805           0 :       while (*line && !spacep (line))
    2806           0 :         line++;
    2807             :     }
    2808           0 :   return gt_delete (server->gt, line, allow_secret);
    2809             : }
    2810             : 
    2811             : 
    2812             : static const char hlp_keylist[] =
    2813             :   "KEYLIST [--secret-only] [<patterns>]\n"
    2814             :   "\n"
    2815             :   "List all certificates or only those specified by PATTERNS.  Each\n"
    2816             :   "pattern shall be a percent-plus escaped certificate specification.";
    2817             : static gpg_error_t
    2818           0 : cmd_keylist (assuan_context_t ctx, char *line)
    2819             : {
    2820             : #define MAX_CMD_KEYLIST_PATTERN 20
    2821           0 :   struct server *server = assuan_get_pointer (ctx);
    2822           0 :   gpgme_tool_t gt = server->gt;
    2823             :   struct result_xml_state state;
    2824             :   gpg_error_t err;
    2825           0 :   int secret_only = 0;
    2826           0 :   int idx, indent=2;
    2827             :   const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
    2828           0 :   const char optstr[] = "--secret-only";
    2829             :   char *p;
    2830             : 
    2831           0 :   if (!strncasecmp (line, optstr, strlen (optstr)))
    2832             :     {
    2833           0 :       secret_only = 1;
    2834           0 :       line += strlen (optstr);
    2835           0 :       while (*line && !spacep (line))
    2836           0 :         line++;
    2837             :     }
    2838             : 
    2839           0 :   idx = 0;
    2840           0 :   for (p=line; *p; line = p)
    2841             :     {
    2842           0 :       while (*p && *p != ' ')
    2843           0 :         p++;
    2844           0 :       if (*p)
    2845           0 :         *p++ = 0;
    2846           0 :       if (*line)
    2847             :         {
    2848           0 :           if (idx+1 == DIM (pattern))
    2849           0 :             return gpg_error (GPG_ERR_TOO_MANY);
    2850           0 :           strcpy_escaped_plus (line, line);
    2851           0 :           pattern[idx++] = line;
    2852             :         }
    2853             :     }
    2854           0 :   pattern[idx] = NULL;
    2855             : 
    2856           0 :   gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
    2857           0 :   gt_write_data (gt, NULL, 0);
    2858           0 :   gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
    2859           0 :   gt_write_data (gt, NULL, 0);
    2860           0 :   result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
    2861           0 :   result_xml_tag_start (&state, "keylist", NULL);
    2862             : 
    2863           0 :   err = gt_keylist_start (server->gt, pattern, secret_only);
    2864           0 :   while (! err)
    2865             :     {
    2866             :       gpgme_key_t key;
    2867             :       gpgme_subkey_t subkey;
    2868             :       gpgme_user_id_t uid;
    2869             : 
    2870           0 :       err = gt_keylist_next (server->gt, &key);
    2871           0 :       if (gpg_err_code (err) == GPG_ERR_EOF)
    2872             :         {
    2873           0 :           err = 0;
    2874           0 :           break;
    2875             :         }
    2876           0 :       else if (! err)
    2877             :         {
    2878           0 :           result_xml_tag_start (&state, "key", NULL);
    2879           0 :           result_add_value (&state, "revoked", key->revoked);
    2880           0 :           result_add_value (&state, "expired", key->expired);
    2881           0 :           result_add_value (&state, "disabled", key->disabled);
    2882           0 :           result_add_value (&state, "invalid", key->invalid);
    2883           0 :           result_add_value (&state, "can-encrypt", key->can_encrypt);
    2884           0 :           result_add_value (&state, "can-sign", key->can_sign);
    2885           0 :           result_add_value (&state, "can-certify", key->can_certify);
    2886           0 :           result_add_value (&state, "can-authenticate", key->can_authenticate);
    2887           0 :           result_add_value (&state, "is-qualified", key->is_qualified);
    2888           0 :           result_add_value (&state, "secret", key->secret);
    2889           0 :           result_add_protocol (&state, "protocol", key->protocol);
    2890           0 :           result_xml_tag_start (&state, "issuer", NULL);
    2891           0 :           result_add_string (&state, "serial", key->issuer_serial);
    2892           0 :           result_add_string (&state, "name", key->issuer_name);
    2893           0 :           result_xml_tag_end (&state);  /* issuer */
    2894           0 :           result_add_string (&state, "chain-id", key->chain_id);
    2895           0 :           result_add_validity (&state, "owner-trust", key->owner_trust);
    2896           0 :           result_xml_tag_start (&state, "subkeys", NULL);
    2897           0 :           subkey = key->subkeys;
    2898           0 :           while (subkey) {
    2899           0 :             result_xml_tag_start (&state, "subkey", NULL);
    2900             :             /* FIXME: more data */
    2901           0 :             result_add_keyid (&state, "keyid", subkey->keyid);
    2902           0 :             if (subkey->fpr)
    2903           0 :               result_add_fpr (&state, "fpr", subkey->fpr);
    2904           0 :             result_add_value (&state, "secret", subkey->secret);
    2905           0 :             result_add_value (&state, "is_cardkey", subkey->is_cardkey);
    2906           0 :             if (subkey->card_number)
    2907           0 :               result_add_string (&state, "card_number", subkey->card_number);
    2908           0 :             if (subkey->curve)
    2909           0 :               result_add_string (&state, "curve", subkey->curve);
    2910           0 :             result_xml_tag_end (&state);  /* subkey */
    2911           0 :             subkey = subkey->next;
    2912             :           }
    2913           0 :           result_xml_tag_end (&state);  /* subkeys */
    2914           0 :           result_xml_tag_start (&state, "uids", NULL);
    2915           0 :           uid = key->uids;
    2916           0 :           while (uid) {
    2917           0 :             result_xml_tag_start (&state, "uid", NULL);
    2918             :             /* FIXME: more data */
    2919           0 :             result_add_string (&state, "uid", uid->uid);
    2920           0 :             result_add_string (&state, "name", uid->name);
    2921           0 :             result_add_string (&state, "email", uid->email);
    2922           0 :             result_add_string (&state, "comment", uid->comment);
    2923           0 :             result_xml_tag_end (&state);  /* uid */
    2924           0 :             uid = uid->next;
    2925             :           }
    2926           0 :           result_xml_tag_end (&state);  /* uids */
    2927           0 :           result_xml_tag_end (&state);  /* key */
    2928           0 :           gpgme_key_unref (key);
    2929             :         }
    2930             :     }
    2931             : 
    2932           0 :   result_xml_tag_end (&state);  /* keylist */
    2933           0 :   gt_write_data (gt, xml_end, strlen (xml_end));
    2934             : 
    2935           0 :   server_reset_fds (server);
    2936             : 
    2937           0 :   return err;
    2938             : }
    2939             : 
    2940             : 
    2941             : static const char hlp_getauditlog[] =
    2942             :   "GETAUDITLOG [--html] [--with-help]\n"
    2943             :   "\n"
    2944             :   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
    2945             :   "the output to the object set by the last OUTPUT command.";
    2946             : static gpg_error_t
    2947           0 : cmd_getauditlog (assuan_context_t ctx, char *line)
    2948             : {
    2949           0 :   struct server *server = assuan_get_pointer (ctx);
    2950             :   gpg_error_t err;
    2951             :   assuan_fd_t out_fd;
    2952             :   char *out_fn;
    2953             :   gpgme_data_t out_data;
    2954           0 :   unsigned int flags = 0;
    2955             : 
    2956           0 :   out_fd = server->output_fd;
    2957           0 :   out_fn = server->output_filename;
    2958           0 :   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
    2959           0 :     return GPG_ERR_ASS_NO_OUTPUT;
    2960           0 :   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    2961             :                          &server->output_stream);
    2962           0 :   if (err)
    2963           0 :     return err;
    2964             : 
    2965           0 :   if (strstr (line, "--html"))
    2966           0 :     flags |= GPGME_AUDITLOG_HTML;
    2967           0 :   if (strstr (line, "--with-help"))
    2968           0 :     flags |= GPGME_AUDITLOG_WITH_HELP;
    2969             : 
    2970           0 :   err = gt_getauditlog (server->gt, out_data, flags);
    2971             : 
    2972           0 :   gpgme_data_release (out_data);
    2973           0 :   server_reset_fds (server);
    2974             : 
    2975           0 :   return err;
    2976             : }
    2977             : 
    2978             : 
    2979             : static gpg_error_t
    2980           0 : cmd_vfs_mount (assuan_context_t ctx, char *line)
    2981             : {
    2982           0 :   struct server *server = assuan_get_pointer (ctx);
    2983             :   char *mount_dir;
    2984             :   gpg_error_t err;
    2985             : 
    2986           0 :   mount_dir = strchr (line, ' ');
    2987           0 :   if (mount_dir)
    2988             :     {
    2989           0 :       *(mount_dir++) = '\0';
    2990           0 :       while (*mount_dir == ' ')
    2991           0 :         mount_dir++;
    2992             :     }
    2993             : 
    2994           0 :   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
    2995             : 
    2996           0 :   return err;
    2997             : }
    2998             : 
    2999             : 
    3000             : static gpg_error_t
    3001           0 : cmd_vfs_create (assuan_context_t ctx, char *line)
    3002             : {
    3003           0 :   struct server *server = assuan_get_pointer (ctx);
    3004             :   gpg_error_t err;
    3005             :   char *end;
    3006             : 
    3007           0 :   end = strchr (line, ' ');
    3008           0 :   if (end)
    3009             :     {
    3010           0 :       *(end++) = '\0';
    3011           0 :       while (*end == ' ')
    3012           0 :         end++;
    3013             :     }
    3014             : 
    3015           0 :   err = gt_vfs_create (server->gt, line, 0);
    3016             : 
    3017           0 :   return err;
    3018             : }
    3019             : 
    3020             : 
    3021             : static const char hlp_passwd[] =
    3022             :   "PASSWD <user-id>\n"
    3023             :   "\n"
    3024             :   "Ask the backend to change the passphrase for the key\n"
    3025             :   "specified by USER-ID.";
    3026             : static gpg_error_t
    3027           0 : cmd_passwd (assuan_context_t ctx, char *line)
    3028             : {
    3029           0 :   struct server *server = assuan_get_pointer (ctx);
    3030             : 
    3031           0 :   return gt_passwd (server->gt, line);
    3032             : }
    3033             : 
    3034             : 
    3035             : 
    3036             : static gpg_error_t
    3037           0 : cmd_result (assuan_context_t ctx, char *line)
    3038             : {
    3039           0 :   struct server *server = assuan_get_pointer (ctx);
    3040           0 :   return gt_result (server->gt, GT_RESULT_ALL);
    3041             : }
    3042             : 
    3043             : 
    3044             : /* STRERROR <err>  */
    3045             : static gpg_error_t
    3046           0 : cmd_strerror (assuan_context_t ctx, char *line)
    3047             : {
    3048             :   gpg_error_t err;
    3049             :   char buf[100];
    3050             : 
    3051           0 :   err = atoi (line);
    3052           0 :   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
    3053             :             gpgme_strsource (err));
    3054           0 :   return assuan_send_data (ctx, buf, strlen (buf));
    3055             : }
    3056             : 
    3057             : 
    3058             : static gpg_error_t
    3059           0 : cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
    3060             : {
    3061             :   gpgme_pubkey_algo_t algo;
    3062             :   char buf[100];
    3063             : 
    3064           0 :   algo = atoi (line);
    3065           0 :   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
    3066           0 :   return assuan_send_data (ctx, buf, strlen (buf));
    3067             : }
    3068             : 
    3069             : 
    3070             : static gpg_error_t
    3071           0 : cmd_hash_algo_name (assuan_context_t ctx, char *line)
    3072             : {
    3073             :   gpgme_hash_algo_t algo;
    3074             :   char buf[100];
    3075             : 
    3076           0 :   algo = atoi (line);
    3077           0 :   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
    3078           0 :   return assuan_send_data (ctx, buf, strlen (buf));
    3079             : }
    3080             : 
    3081             : 
    3082             : static const char hlp_identify[] =
    3083             :   "IDENTIY\n"
    3084             :   "\n"
    3085             :   "Identify the type of data set with the INPUT command.";
    3086             : static gpg_error_t
    3087           0 : cmd_identify (assuan_context_t ctx, char *line)
    3088             : {
    3089           0 :   struct server *server = assuan_get_pointer (ctx);
    3090             :   gpg_error_t err;
    3091             :   assuan_fd_t inp_fd;
    3092             :   char *inp_fn;
    3093             :   gpgme_data_t inp_data;
    3094             : 
    3095           0 :   inp_fd = server->input_fd;
    3096           0 :   inp_fn = server->input_filename;
    3097           0 :   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
    3098           0 :     return GPG_ERR_ASS_NO_INPUT;
    3099             : 
    3100           0 :   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    3101             :                          &server->input_stream);
    3102           0 :   if (err)
    3103           0 :     return err;
    3104             : 
    3105           0 :   err = gt_identify (server->gt, inp_data);
    3106             : 
    3107           0 :   gpgme_data_release (inp_data);
    3108           0 :   server_reset_fds (server);
    3109             : 
    3110           0 :   return err;
    3111             : }
    3112             : 
    3113             : 
    3114             : static const char hlp_spawn[] =
    3115             :   "SPAWN PGM [args]\n"
    3116             :   "\n"
    3117             :   "Run program PGM with stdin connected to the INPUT source;\n"
    3118             :   "stdout and stderr to the OUTPUT source.";
    3119             : static gpg_error_t
    3120           0 : cmd_spawn (assuan_context_t ctx, char *line)
    3121             : {
    3122           0 :   struct server *server = assuan_get_pointer (ctx);
    3123             :   gpg_error_t err;
    3124             :   assuan_fd_t inp_fd;
    3125             :   char *inp_fn;
    3126             :   assuan_fd_t out_fd;
    3127             :   char *out_fn;
    3128           0 :   gpgme_data_t inp_data = NULL;
    3129           0 :   gpgme_data_t out_data = NULL;
    3130             : 
    3131           0 :   inp_fd = server->input_fd;
    3132           0 :   inp_fn = server->input_filename;
    3133           0 :   out_fd = server->output_fd;
    3134           0 :   out_fn = server->output_filename;
    3135           0 :   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
    3136             :     {
    3137           0 :       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
    3138             :                              &server->input_stream);
    3139           0 :       if (err)
    3140           0 :         return err;
    3141             :     }
    3142           0 :   if (out_fd != ASSUAN_INVALID_FD || out_fn)
    3143             :     {
    3144           0 :       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
    3145             :                              &server->output_stream);
    3146           0 :       if (err)
    3147             :         {
    3148           0 :           gpgme_data_release (inp_data);
    3149           0 :           return err;
    3150             :         }
    3151             :     }
    3152             : 
    3153           0 :   err = gt_spawn (server->gt, line, inp_data, out_data);
    3154             : 
    3155           0 :   gpgme_data_release (inp_data);
    3156           0 :   gpgme_data_release (out_data);
    3157             : 
    3158           0 :   server_reset_fds (server);
    3159             : 
    3160           0 :   return err;
    3161             : }
    3162             : 
    3163             : 
    3164             : /* Tell the assuan library about our commands.  */
    3165             : static gpg_error_t
    3166           0 : register_commands (assuan_context_t ctx)
    3167             : {
    3168             :   gpg_error_t err;
    3169             :   static struct {
    3170             :     const char *name;
    3171             :     assuan_handler_t handler;
    3172             :     const char * const help;
    3173             :   } table[] = {
    3174             :     /* RESET, BYE are implicit.  */
    3175             :     { "VERSION", cmd_version, hlp_version },
    3176             :     /* TODO: Set engine info.  */
    3177             :     { "ENGINE", cmd_engine, hlp_engine },
    3178             :     { "PROTOCOL", cmd_protocol, hlp_protocol },
    3179             :     { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
    3180             :     { "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
    3181             :     { "ARMOR", cmd_armor, hlp_armor },
    3182             :     { "TEXTMODE", cmd_textmode, hlp_textmode },
    3183             :     { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
    3184             :     { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
    3185             :     { "INPUT", cmd_input, hlp_input },
    3186             :     { "OUTPUT", cmd_output, hlp_output },
    3187             :     { "MESSAGE", cmd_message, hlp_message },
    3188             :     { "RECIPIENT", cmd_recipient, hlp_recipient },
    3189             :     { "SIGNER", cmd_signer, hlp_signer },
    3190             :     { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
    3191             :      /* TODO: SIGNOTATION missing. */
    3192             :      /* TODO: Could add wait interface if we allow more than one context */
    3193             :      /* and add _START variants. */
    3194             :      /* TODO: Could add data interfaces if we allow multiple data objects. */
    3195             :     { "DECRYPT", cmd_decrypt, hlp_decrypt },
    3196             :     { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
    3197             :     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
    3198             :     { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
    3199             :     { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
    3200             :     { "SIGN", cmd_sign, hlp_sign },
    3201             :     { "VERIFY", cmd_verify, hlp_verify },
    3202             :     { "IMPORT", cmd_import, hlp_import },
    3203             :     { "EXPORT", cmd_export, hlp_export },
    3204             :     { "GENKEY", cmd_genkey },
    3205             :     { "DELETE", cmd_delete },
    3206             :     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
    3207             :     { "KEYLIST", cmd_keylist, hlp_keylist },
    3208             :     { "LISTKEYS", cmd_keylist, hlp_keylist },
    3209             :     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
    3210             :     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
    3211             :     /* TODO: ASSUAN */
    3212             :     { "VFS_MOUNT", cmd_vfs_mount },
    3213             :     { "MOUNT", cmd_vfs_mount },
    3214             :     { "VFS_CREATE", cmd_vfs_create },
    3215             :     { "CREATE", cmd_vfs_create },
    3216             :     /* TODO: GPGCONF  */
    3217             :     { "RESULT", cmd_result },
    3218             :     { "STRERROR", cmd_strerror },
    3219             :     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
    3220             :     { "HASH_ALGO_NAME", cmd_hash_algo_name },
    3221             :     { "PASSWD", cmd_passwd, hlp_passwd },
    3222             :     { "IDENTIFY", cmd_identify, hlp_identify },
    3223             :     { "SPAWN", cmd_spawn, hlp_spawn },
    3224             :     { NULL }
    3225             :   };
    3226             :   int idx;
    3227             : 
    3228           0 :   for (idx = 0; table[idx].name; idx++)
    3229             :     {
    3230           0 :       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
    3231             :                                      table[idx].help);
    3232           0 :       if (err)
    3233           0 :         return err;
    3234             :     }
    3235           0 :   return 0;
    3236             : }
    3237             : 
    3238             : 
    3239             : void
    3240           0 : gpgme_server (gpgme_tool_t gt)
    3241             : {
    3242             :   gpg_error_t err;
    3243             :   assuan_fd_t filedes[2];
    3244             :   struct server server;
    3245             :   static const char hello[] = ("GPGME-Tool " VERSION " ready");
    3246             : 
    3247           0 :   memset (&server, 0, sizeof (server));
    3248           0 :   server.input_fd = ASSUAN_INVALID_FD;
    3249           0 :   server.output_fd = ASSUAN_INVALID_FD;
    3250           0 :   server.message_fd = ASSUAN_INVALID_FD;
    3251           0 :   server.input_enc = GPGME_DATA_ENCODING_NONE;
    3252           0 :   server.output_enc = GPGME_DATA_ENCODING_NONE;
    3253           0 :   server.message_enc = GPGME_DATA_ENCODING_NONE;
    3254             : 
    3255           0 :   server.gt = gt;
    3256           0 :   gt->write_status = server_write_status;
    3257           0 :   gt->write_status_hook = &server;
    3258           0 :   gt->write_data = server_write_data;
    3259           0 :   gt->write_data_hook = &server;
    3260             : 
    3261             :   /* We use a pipe based server so that we can work from scripts.
    3262             :      assuan_init_pipe_server will automagically detect when we are
    3263             :      called with a socketpair and ignore FIELDES in this case. */
    3264             : #ifdef HAVE_W32CE_SYSTEM
    3265             :   filedes[0] = ASSUAN_STDIN;
    3266             :   filedes[1] = ASSUAN_STDOUT;
    3267             : #else
    3268           0 :   filedes[0] = assuan_fdopen (0);
    3269           0 :   filedes[1] = assuan_fdopen (1);
    3270             : #endif
    3271           0 :   err = assuan_new (&server.assuan_ctx);
    3272           0 :   if (err)
    3273           0 :     log_error (1, err, "can't create assuan context");
    3274             : 
    3275           0 :   assuan_set_pointer (server.assuan_ctx, &server);
    3276             : 
    3277           0 :   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
    3278           0 :   if (err)
    3279           0 :     log_error (1, err, "can't initialize assuan server");
    3280           0 :   err = register_commands (server.assuan_ctx);
    3281           0 :   if (err)
    3282           0 :     log_error (1, err, "can't register assuan commands");
    3283           0 :   assuan_set_hello_line (server.assuan_ctx, hello);
    3284             : 
    3285           0 :   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
    3286             : 
    3287             : #define DBG_ASSUAN 0
    3288             :   if (DBG_ASSUAN)
    3289             :     assuan_set_log_stream (server.assuan_ctx, log_stream);
    3290             : 
    3291             :   for (;;)
    3292             :     {
    3293           0 :       err = assuan_accept (server.assuan_ctx);
    3294           0 :       if (err == -1)
    3295           0 :         break;
    3296           0 :       else if (err)
    3297             :         {
    3298           0 :           log_error (0, err, "assuan accept problem");
    3299           0 :           break;
    3300             :         }
    3301             : 
    3302           0 :       err = assuan_process (server.assuan_ctx);
    3303           0 :       if (err)
    3304           0 :         log_error (0, err, "assuan processing failed");
    3305           0 :     }
    3306             : 
    3307           0 :   assuan_release (server.assuan_ctx);
    3308           0 : }
    3309             : 
    3310             : 
    3311             : 
    3312             : static const char *
    3313           0 : my_strusage( int level )
    3314             : {
    3315             :   const char *p;
    3316             : 
    3317           0 :   switch (level)
    3318             :     {
    3319           0 :     case 11: p = "gpgme-tool"; break;
    3320           0 :     case 13: p = PACKAGE_VERSION; break;
    3321           0 :     case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
    3322           0 :     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
    3323             :     case 1:
    3324             :     case 40:
    3325           0 :       p = "Usage: gpgme-tool [OPTIONS] [COMMANDS]";
    3326           0 :       break;
    3327             :     case 41:
    3328           0 :       p = "GPGME Tool -- Assuan server exposing GPGME operations\n";
    3329           0 :       break;
    3330             :     case 42:
    3331           0 :       p = "1"; /* Flag print 40 as part of 41. */
    3332           0 :       break;
    3333           0 :     default: p = NULL; break;
    3334             :     }
    3335           0 :   return p;
    3336             : }
    3337             : 
    3338             : 
    3339             : int
    3340           0 : main (int argc, char *argv[])
    3341             : {
    3342             :   static ARGPARSE_OPTS opts[] = {
    3343             :     ARGPARSE_c  ('s', "server",      "Server mode"),
    3344             :     ARGPARSE_s_s(501, "gpg-binary",  "|FILE|Use FILE for the GPG backend"),
    3345             :     ARGPARSE_c  (502, "lib-version", "Show library version"),
    3346             :     ARGPARSE_end()
    3347             :   };
    3348           0 :   ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
    3349           0 :   enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd = CMD_DEFAULT;
    3350           0 :   const char *gpg_binary = NULL;
    3351             :   struct gpgme_tool gt;
    3352             :   gpg_error_t err;
    3353           0 :   int needgt = 1;
    3354             : 
    3355           0 :   set_strusage (my_strusage);
    3356             : 
    3357             : #ifdef HAVE_SETLOCALE
    3358           0 :   setlocale (LC_ALL, "");
    3359             : #endif
    3360           0 :   gpgme_check_version (NULL);
    3361             : #ifdef LC_CTYPE
    3362           0 :   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
    3363             : #endif
    3364             : #ifdef LC_MESSAGES
    3365           0 :   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
    3366             : #endif
    3367             : 
    3368           0 :   log_init ();
    3369             : 
    3370           0 :   while (arg_parse  (&pargs, opts))
    3371             :     {
    3372           0 :       switch (pargs.r_opt)
    3373             :         {
    3374           0 :         case 's': cmd = CMD_SERVER; break;
    3375           0 :         case 501: gpg_binary = pargs.r.ret_str; break;
    3376           0 :         case 502: cmd = CMD_LIBVERSION; break;
    3377             :         default:
    3378           0 :           pargs.err = ARGPARSE_PRINT_WARNING;
    3379           0 :           break;
    3380             :         }
    3381             :     }
    3382             : 
    3383           0 :   if (cmd == CMD_LIBVERSION)
    3384           0 :     needgt = 0;
    3385             : 
    3386           0 :   if (needgt && gpg_binary)
    3387             :     {
    3388           0 :       if (access (gpg_binary, X_OK))
    3389           0 :         err = gpg_error_from_syserror ();
    3390             :       else
    3391           0 :         err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
    3392             :                                      gpg_binary, NULL);
    3393           0 :       if (err)
    3394           0 :         log_error (1, err, "error witching OpenPGP engine to '%s'",
    3395             :                    gpg_binary);
    3396             :     }
    3397             : 
    3398           0 :   if (needgt)
    3399           0 :     gt_init (&gt);
    3400             : 
    3401           0 :   switch (cmd)
    3402             :     {
    3403             :     case CMD_DEFAULT:
    3404             :     case CMD_SERVER:
    3405           0 :       gpgme_server (&gt);
    3406           0 :       break;
    3407             : 
    3408             :     case CMD_LIBVERSION:
    3409           0 :       printf ("Version from header: %s (0x%06x)\n",
    3410             :               GPGME_VERSION, GPGME_VERSION_NUMBER);
    3411           0 :       printf ("Version from binary: %s\n", gpgme_check_version (NULL));
    3412           0 :       printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
    3413           0 :       break;
    3414             :     }
    3415             : 
    3416           0 :   if (needgt)
    3417           0 :     gpgme_release (gt.ctx);
    3418             : 
    3419             : #ifdef HAVE_W32CE_SYSTEM
    3420             :   /* Give the buggy ssh server time to flush the output buffers.  */
    3421             :   Sleep (300);
    3422             : #endif
    3423             : 
    3424           0 :   return 0;
    3425             : }

Generated by: LCOV version 1.11