LCOV - code coverage report
Current view: top level - src - gpgme-tool.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1464 0.0 %
Date: 2015-11-05 17:14:26 Functions: 0 129 0.0 %

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

Generated by: LCOV version 1.11