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

Generated by: LCOV version 1.13