887af7307b242a35c59afb9b8a102128fe2cb9e9
[gpgme.git] / src / edit.c
1 /* edit.c - Key edit function.
2    Copyright (C) 2002, 2003, 2004 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 #include <stdlib.h>
25
26 #include "gpgme.h"
27 #include "debug.h"
28 #include "context.h"
29 #include "ops.h"
30 #include "util.h"
31
32
33 \f
34 typedef struct
35 {
36   /* The user callback function and its hook value.  */
37   gpgme_interact_cb_t fnc;
38   gpgme_edit_cb_t fnc_old;
39   void *fnc_value;
40 } *op_data_t;
41
42 \f
43 static gpgme_error_t
44 edit_status_handler (void *priv, gpgme_status_code_t status, char *args)
45 {
46   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
47   gpgme_error_t err;
48   void *hook;
49   op_data_t opd;
50
51   err = _gpgme_passphrase_status_handler (priv, status, args);
52   if (err)
53     return err;
54
55   err = _gpgme_progress_status_handler (priv, status, args);
56   if (err)
57     return err;
58
59   err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, -1, NULL);
60   opd = hook;
61   if (err)
62     return err;
63
64   if (opd->fnc_old)
65     return (*opd->fnc_old) (opd->fnc_value, status, args, -1);
66
67   return (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
68                       args, -1);
69 }
70
71
72 static gpgme_error_t
73 command_handler (void *priv, gpgme_status_code_t status, const char *args,
74                  int fd, int *processed_r)
75 {
76   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
77   gpgme_error_t err;
78   int processed = 0;
79
80   if (ctx->passphrase_cb)
81     {
82       err = _gpgme_passphrase_command_handler (ctx, status, args,
83                                                fd, &processed);
84       if (err)
85         return err;
86     }
87   else
88     err = 0;
89
90   if (!processed)
91     {
92       void *hook;
93       op_data_t opd;
94
95       err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, -1, NULL);
96       opd = hook;
97       if (err)
98         return err;
99
100       if (opd->fnc_old)
101         err = (*opd->fnc_old) (opd->fnc_value, status, args, fd);
102       else
103         err = (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
104                            args, fd);
105
106       if (gpg_err_code (err) == GPG_ERR_FALSE)
107         err = 0;
108       else
109         processed = 1;
110     }
111
112   *processed_r = processed;
113   return err;
114 }
115
116
117 static gpgme_error_t
118 interact_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
119                 unsigned int flags,
120                 gpgme_interact_cb_t fnc, void *fnc_value, gpgme_data_t out)
121 {
122   gpgme_error_t err;
123   void *hook;
124   op_data_t opd;
125
126   err = _gpgme_op_reset (ctx, synchronous);
127   if (err)
128     return err;
129
130   if (!fnc || !out)
131     return gpg_error (GPG_ERR_INV_VALUE);
132
133   err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
134   opd = hook;
135   if (err)
136     return err;
137
138   opd->fnc = fnc;
139   opd->fnc_old = NULL;
140   opd->fnc_value = fnc_value;
141
142   err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
143                                            ctx, out);
144   if (err)
145     return err;
146
147   _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
148
149   return _gpgme_engine_op_edit (ctx->engine,
150                                 (flags & GPGME_INTERACT_CARD)? 1: 0,
151                                 key, out, ctx);
152 }
153
154
155 gpgme_error_t
156 gpgme_op_interact_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
157                          gpgme_interact_cb_t fnc, void *fnc_value,
158                          gpgme_data_t out)
159 {
160   gpgme_error_t err;
161
162   TRACE_BEG5 (DEBUG_CTX, "gpgme_op_interact_start", ctx,
163               "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
164               key, flags,fnc, fnc_value, out);
165
166   if (!ctx)
167     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
168
169   err = interact_start (ctx, 0, key, flags, fnc, fnc_value, out);
170   return err;
171 }
172
173
174 gpgme_error_t
175 gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
176                    gpgme_interact_cb_t fnc, void *fnc_value,
177                    gpgme_data_t out)
178 {
179   gpgme_error_t err;
180
181   TRACE_BEG5 (DEBUG_CTX, "gpgme_op_interact", ctx,
182               "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
183               key, flags,fnc, fnc_value, out);
184
185   if (!ctx)
186     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
187
188   err = interact_start (ctx, 1, key, flags, fnc, fnc_value, out);
189   if (!err)
190     err = _gpgme_wait_one (ctx);
191   return err;
192 }
193
194
195
196 \f
197 /* The deprectated interface.  */
198 static gpgme_error_t
199 edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
200             gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
201 {
202   gpgme_error_t err;
203   void *hook;
204   op_data_t opd;
205
206   err = _gpgme_op_reset (ctx, synchronous);
207   if (err)
208     return err;
209
210   if (!fnc || !out)
211     return gpg_error (GPG_ERR_INV_VALUE);
212
213   err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
214   opd = hook;
215   if (err)
216     return err;
217
218   opd->fnc = NULL;
219   opd->fnc_old = fnc;
220   opd->fnc_value = fnc_value;
221
222   err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
223                                            ctx, out);
224   if (err)
225     return err;
226
227   _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
228
229   return _gpgme_engine_op_edit (ctx->engine, type, key, out, ctx);
230 }
231
232
233 gpgme_error_t
234 gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
235                      gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
236 {
237   gpgme_error_t err;
238
239   TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit_start", ctx,
240               "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
241               (key && key->subkeys && key->subkeys->fpr) ?
242               key->subkeys->fpr : "invalid", fnc, fnc_value, out);
243
244   if (!ctx)
245     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
246
247   err = edit_start (ctx, 0, 0, key, fnc, fnc_value, out);
248   return err;
249 }
250
251
252 /* Edit the key KEY.  Send status and command requests to FNC and
253    output of edit commands to OUT.  */
254 gpgme_error_t
255 gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
256                gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
257 {
258   gpgme_error_t err;
259
260   TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit", ctx,
261               "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
262               (key && key->subkeys && key->subkeys->fpr) ?
263               key->subkeys->fpr : "invalid", fnc, fnc_value, out);
264
265   if (!ctx)
266     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
267
268   err = edit_start (ctx, 1, 0, key, fnc, fnc_value, out);
269
270   if (!err)
271     err = _gpgme_wait_one (ctx);
272   return TRACE_ERR (err);
273 }
274
275 \f
276 gpgme_error_t
277 gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
278                           gpgme_edit_cb_t fnc, void *fnc_value,
279                           gpgme_data_t out)
280 {
281   gpgme_error_t err;
282
283   TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit_start", ctx,
284               "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
285               (key && key->subkeys && key->subkeys->fpr) ?
286               key->subkeys->fpr : "invalid", fnc, fnc_value, out);
287
288   if (!ctx)
289     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
290
291   err = edit_start (ctx, 0, 1, key, fnc, fnc_value, out);
292   return err;
293 }
294
295
296 /* Edit the card for the key KEY.  Send status and command requests to
297    FNC and output of edit commands to OUT.  */
298 gpgme_error_t
299 gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
300                     gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
301 {
302   gpgme_error_t err;
303
304   TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit", ctx,
305               "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
306               (key && key->subkeys && key->subkeys->fpr) ?
307               key->subkeys->fpr : "invalid", fnc, fnc_value, out);
308
309   if (!ctx)
310     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
311
312   err = edit_start (ctx, 1, 1, key, fnc, fnc_value, out);
313   if (!err)
314     err = _gpgme_wait_one (ctx);
315   return TRACE_ERR (err);
316 }