2009-10-22 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / g13.c
1 /* g13.c - g13 support in GPGME
2    Copyright (C) 2009 g10 Code GmbH
3
4    This file is part of GPGME.
5  
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10    
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15    
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdlib.h>
26
27 #include "gpgme.h"
28 #include "context.h"
29 #include "ops.h"
30 #include "util.h"
31
32 typedef struct
33 {
34   struct _gpgme_op_g13_result result;
35 } *op_data_t;
36
37
38 \f
39 /* This callback is used to return the status of the assuan command
40    back rather than transmission errors.  */
41 static gpgme_error_t
42 result_cb (void *priv, gpgme_error_t result)
43 {
44   gpgme_ctx_t ctx = (gpgme_ctx_t)priv;
45   gpgme_error_t err;
46   void *hook;
47   op_data_t opd;
48
49   err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL);
50   opd = hook;
51   if (err)
52     return err;
53   if (!opd)
54     return gpg_error (GPG_ERR_INTERNAL);
55
56   opd->result.err = result;
57   return 0;
58 }
59
60
61 gpgme_g13_result_t
62 gpgme_op_g13_result (gpgme_ctx_t ctx)
63 {
64   gpgme_error_t err;
65   void *hook;
66   op_data_t opd;
67
68   err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL);
69   opd = hook;
70   /* Check in case this function is used without having run a command
71      before.  */
72   if (err || !opd)
73     return NULL;
74
75   return &opd->result;
76 }
77
78
79 static gpgme_error_t
80 opg13_start (gpgme_ctx_t ctx, int synchronous,
81                 const char *command,
82                 gpgme_assuan_data_cb_t data_cb,
83                 void *data_cb_value,
84                 gpgme_assuan_inquire_cb_t inq_cb,
85                 void *inq_cb_value,
86                 gpgme_assuan_status_cb_t status_cb,
87                 void *status_cb_value)
88 {
89   gpgme_error_t err;
90   void *hook;
91   op_data_t opd;
92
93   if (!command || !*command)
94     return gpg_error (GPG_ERR_INV_VALUE);
95
96   /* The flag value 256 is used to suppress an engine reset.  This is
97      required to keep the connection running.  */
98   err = _gpgme_op_reset (ctx, ((synchronous & 255) | 256));
99   if (err)
100     return err;
101
102   err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, sizeof (*opd), NULL);
103   opd = hook;
104   if (err)
105     return err;
106   opd->result.err = gpg_error (GPG_ERR_UNFINISHED);
107
108   return _gpgme_engine_op_assuan_transact (ctx->engine, command,
109                                            result_cb, ctx,
110                                            data_cb, data_cb_value,
111                                            inq_cb, inq_cb_value,
112                                            status_cb, status_cb_value);
113 }
114
115
116
117 /* XXXX.  This is the asynchronous variant. */
118 static gpgme_error_t
119 gpgme_op_g13_transact_start (gpgme_ctx_t ctx, 
120                              const char *command,
121                              gpgme_assuan_data_cb_t data_cb,
122                              void *data_cb_value,
123                              gpgme_assuan_inquire_cb_t inq_cb,
124                              void *inq_cb_value,
125                              gpgme_assuan_status_cb_t status_cb,
126                              void *status_cb_value)
127 {
128   return opg13_start (ctx, 0, command, data_cb, data_cb_value,
129                       inq_cb, inq_cb_value, status_cb, status_cb_value);
130 }
131
132
133 /* XXXX.  This is the synchronous variant. */
134 static gpgme_error_t
135 gpgme_op_g13_transact (gpgme_ctx_t ctx,
136                        const char *command,
137                        gpgme_assuan_data_cb_t data_cb,
138                        void *data_cb_value,
139                        gpgme_assuan_inquire_cb_t inq_cb,
140                        void *inq_cb_value,
141                        gpgme_assuan_status_cb_t status_cb,
142                        void *status_cb_value)
143 {
144   gpgme_error_t err;
145   
146   err = opg13_start (ctx, 1, command, data_cb, data_cb_value,
147                      inq_cb, inq_cb_value, status_cb, status_cb_value);
148   if (!err)
149     err = _gpgme_wait_one (ctx);
150   return err;
151 }
152
153 \f
154 /* The actual exported interface follows.  */
155
156 static gpg_error_t
157 get_err (gpgme_ctx_t ctx)
158 {
159   gpgme_g13_result_t res;
160
161   res = gpgme_op_g13_result (ctx);
162   if (! res)
163     return gpg_error (GPG_ERR_GENERAL);
164
165   return res->err;
166 }
167
168
169 /* The container is automatically unmounted when the context is reset
170    or destroyed.  This is a synchronous convenience interface, which
171    automatically returns an operation error if there is no
172    transmission error.  */
173 gpgme_error_t
174 gpgme_op_g13_mount (gpgme_ctx_t ctx, const char *container_file,
175                     const char *mount_dir, int flags)
176 {
177   gpg_error_t err;
178   char *cmd;
179   char *container_file_esc = NULL;
180   
181   err = _gpgme_encode_percent_string (container_file, &container_file_esc, 0);
182   if (err)
183     return err;
184
185   if (asprintf (&cmd, "OPEN -- %s", container_file_esc) < 0)
186     {
187       err = gpg_error_from_syserror ();
188       free (container_file_esc);
189       return err;
190     }
191   free (container_file_esc);
192
193   err = gpgme_op_g13_transact (ctx, cmd, NULL, NULL, NULL, NULL,
194                                NULL, NULL);
195   free (cmd);
196   err = err || get_err (ctx);
197   if (err)
198     return err;
199
200   if (mount_dir)
201     {
202       char *mount_dir_esc = NULL;
203
204       err = _gpgme_encode_percent_string (mount_dir, &mount_dir_esc, 0);
205       if (err)
206         return err;
207
208       if (asprintf (&cmd, "MOUNT -- %s", mount_dir_esc) < 0)
209         {
210           err = gpg_error_from_syserror ();
211           free (mount_dir_esc);
212           return err;
213         }
214       free (mount_dir_esc);
215     }
216   else
217     {
218       if (asprintf (&cmd, "MOUNT") < 0)
219         return gpg_error_from_syserror ();
220     }
221     
222   err = gpgme_op_g13_transact (ctx, cmd, NULL, NULL, NULL, NULL,
223                                NULL, NULL);
224   free (cmd);
225
226   /* Note: in symmetry with the asynchronous variant, we don't return 
227      the error in the result structure here, if any.  */
228   return err;
229 }