2010-05-06 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / vfs-create.c
1 /* vfs-create.c - vfs create 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 "debug.h"
29 #include "context.h"
30 #include "ops.h"
31 #include "util.h"
32
33 static gpgme_error_t
34 vfs_start (gpgme_ctx_t ctx, int synchronous,
35            const char *command,
36            gpgme_assuan_data_cb_t data_cb,
37            void *data_cb_value,
38            gpgme_assuan_inquire_cb_t inq_cb,
39            void *inq_cb_value,
40            gpgme_assuan_status_cb_t status_cb,
41            void *status_cb_value)
42 {
43   gpgme_error_t err;
44
45   if (!command || !*command)
46     return gpg_error (GPG_ERR_INV_VALUE);
47
48   /* The flag value 256 is used to suppress an engine reset.  This is
49      required to keep the connection running.  */
50   err = _gpgme_op_reset (ctx, ((synchronous & 255) | 256));
51   if (err)
52     return err;
53
54   return _gpgme_engine_op_assuan_transact (ctx->engine, command,
55                                            data_cb, data_cb_value,
56                                            inq_cb, inq_cb_value,
57                                            status_cb, status_cb_value);
58 }
59
60
61 #if 0
62 /* XXXX.  This is the asynchronous variant. */
63 static gpgme_error_t
64 gpgme_op_vfs_transact_start (gpgme_ctx_t ctx, 
65                              const char *command,
66                              gpgme_assuan_data_cb_t data_cb,
67                              void *data_cb_value,
68                              gpgme_assuan_inquire_cb_t inq_cb,
69                              void *inq_cb_value,
70                              gpgme_assuan_status_cb_t status_cb,
71                              void *status_cb_value)
72 {
73   return vfs_start (ctx, 0, command, data_cb, data_cb_value,
74                     inq_cb, inq_cb_value, status_cb, status_cb_value);
75 }
76 #endif
77
78
79 /* XXXX.  This is the synchronous variant. */
80 static gpgme_error_t
81 gpgme_op_vfs_transact (gpgme_ctx_t ctx,
82                        const char *command,
83                        gpgme_assuan_data_cb_t data_cb,
84                        void *data_cb_value,
85                        gpgme_assuan_inquire_cb_t inq_cb,
86                        void *inq_cb_value,
87                        gpgme_assuan_status_cb_t status_cb,
88                        void *status_cb_value,
89                        gpgme_error_t *op_err)
90 {
91   gpgme_error_t err;
92   
93   err = vfs_start (ctx, 1, command, data_cb, data_cb_value,
94                    inq_cb, inq_cb_value, status_cb, status_cb_value);
95   if (!err)
96     err = _gpgme_wait_one_ext (ctx, op_err);
97   return err;
98 }
99
100 \f
101 /* The actual exported interface follows.  */
102
103 /* The container is automatically uncreateed when the context is reset
104    or destroyed.  This is a synchronous convenience interface, which
105    automatically returns an operation error if there is no
106    transmission error.  */
107 static gpgme_error_t
108 _gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
109                       const char *container_file, unsigned int flags,
110                       gpgme_error_t *op_err)
111 {
112   gpg_error_t err;
113   char *cmd;
114   char *container_file_esc = NULL;
115   int i;
116
117   /* We want to encourage people to check error values, so not getting
118      them is discouraged here.  Also makes our code easier.  */
119   if (! op_err)
120     return gpg_error (GPG_ERR_INV_VALUE);
121
122   err = _gpgme_encode_percent_string (container_file, &container_file_esc, 0);
123   if (err)
124     return err;
125
126   i = 0;
127   while (!err && recp[i])
128     {
129       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
130         {
131           free (container_file_esc);
132           return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
133         }
134
135       if (asprintf (&cmd, "RECIPIENT %s", recp[i]->subkeys->fpr) < 0)
136         {
137           err = gpg_error_from_syserror ();
138           free (container_file_esc);
139           return err;
140         }
141       
142       err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL,
143                                    NULL, NULL, op_err);
144       free (cmd);
145       if (err || *op_err)
146         {
147           free (container_file_esc);
148           return err;
149         }
150       recp++;
151     }
152
153   if (asprintf (&cmd, "CREATE -- %s", container_file_esc) < 0)
154     {
155       err = gpg_error_from_syserror ();
156       free (container_file_esc);
157       return err;
158     }
159   free (container_file_esc);
160     
161   err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL,
162                                NULL, NULL, op_err);
163   free (cmd);
164
165   return err;
166 }
167
168
169 gpgme_error_t
170 gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
171                       const char *container_file, unsigned int flags,
172                       gpgme_error_t *op_err)
173 {
174   gpg_error_t err;
175
176   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_vfs_create", ctx,
177               "container_file=%s, flags=0x%x, op_err=%p",
178               container_file, flags, op_err);
179
180   if (_gpgme_debug_trace () && recp)
181     {
182       int i = 0;
183       
184       while (recp[i])
185         {
186           TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
187                       (recp[i]->subkeys && recp[i]->subkeys->fpr) ? 
188                       recp[i]->subkeys->fpr : "invalid");
189           i++;
190         }
191     }
192
193   err = _gpgme_op_vfs_create (ctx, recp, container_file, flags, op_err);
194   return TRACE_ERR (err);
195 }
196