808eac87355276d716f37090470bdb572e6617da
[gpgme.git] / src / op-support.c
1 /* op-support.c - Supporting functions.
2    Copyright (C) 2002, 2003, 2004, 2007 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26 #ifdef HAVE_LOCALE_H
27 #include <locale.h>
28 #endif
29
30 #include "gpgme.h"
31 #include "context.h"
32 #include "ops.h"
33 #include "util.h"
34
35 \f
36 gpgme_error_t
37 _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook,
38                        int size, void (*cleanup) (void *))
39 {
40   struct ctx_op_data *data;
41
42   if (!ctx)
43     return gpg_error (GPG_ERR_INV_VALUE);
44
45   data = ctx->op_data;
46   while (data && data->type != type)
47     data = data->next;
48   if (!data)
49     {
50       if (size < 0)
51         {
52           *hook = NULL;
53           return 0;
54         }
55
56       data = calloc (1, sizeof (struct ctx_op_data) + size);
57       if (!data)
58         return gpg_error_from_errno (errno);
59       data->magic = CTX_OP_DATA_MAGIC;
60       data->next = ctx->op_data;
61       data->type = type;
62       data->cleanup = cleanup;
63       data->hook = (void *) (((char *) data) + sizeof (struct ctx_op_data));
64       data->references = 1;
65       ctx->op_data = data;
66     }
67   *hook = data->hook;
68   return 0;
69 }
70
71
72 /* type is: 0: asynchronous operation (use global or user event loop).
73             1: synchronous operation (always use private event loop).
74             2: asynchronous private operation (use private or user
75             event loop).
76             256: Modification flag to suppress the engine reset.
77 */
78 gpgme_error_t
79 _gpgme_op_reset (gpgme_ctx_t ctx, int type)
80 {
81   gpgme_error_t err = 0;
82   struct gpgme_io_cbs io_cbs;
83   int no_reset = (type & 256);
84   int reuse_engine = 0;
85
86   type &= 255;
87
88   _gpgme_release_result (ctx);
89   LOCK (ctx->lock);
90   ctx->canceled = 0;
91   UNLOCK (ctx->lock);
92
93   if (ctx->engine && no_reset)
94     reuse_engine = 1;
95   else if (ctx->engine)
96     {
97       /* Attempt to reset an existing engine.  */
98
99       err = _gpgme_engine_reset (ctx->engine);
100       if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
101         {
102           _gpgme_engine_release (ctx->engine);
103           ctx->engine = NULL;
104         }
105     }
106
107   if (!ctx->engine)
108     {
109       gpgme_engine_info_t info;
110       info = ctx->engine_info;
111       while (info && info->protocol != ctx->protocol)
112         info = info->next;
113
114       if (!info)
115         return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
116
117       /* Create an engine object.  */
118       err = _gpgme_engine_new (info, &ctx->engine);
119       if (err)
120         return err;
121     }
122
123   if (!reuse_engine)
124     {
125       err = 0;
126 #ifdef LC_CTYPE
127       err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype);
128 #endif
129 #ifdef LC_MESSAGES
130       if (!err)
131         err = _gpgme_engine_set_locale (ctx->engine,
132                                         LC_MESSAGES, ctx->lc_messages);
133 #endif
134       if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
135         err = 0;
136       if (err)
137         {
138           _gpgme_engine_release (ctx->engine);
139           ctx->engine = NULL;
140           return err;
141         }
142     }
143
144   if (ctx->sub_protocol != GPGME_PROTOCOL_DEFAULT)
145     {
146       err = _gpgme_engine_set_protocol (ctx->engine, ctx->sub_protocol);
147       if (err)
148         return err;
149     }
150
151   if (type == 1 || (type == 2 && !ctx->io_cbs.add))
152     {
153       /* Use private event loop.  */
154       io_cbs.add = _gpgme_add_io_cb;
155       io_cbs.add_priv = ctx;
156       io_cbs.remove = _gpgme_remove_io_cb;
157       io_cbs.event = _gpgme_wait_private_event_cb;
158       io_cbs.event_priv = ctx;
159     }
160   else if (! ctx->io_cbs.add)
161     {
162       /* Use global event loop.  */
163       io_cbs.add = _gpgme_add_io_cb;
164       io_cbs.add_priv = ctx;
165       io_cbs.remove = _gpgme_remove_io_cb;
166       io_cbs.event = _gpgme_wait_global_event_cb;
167       io_cbs.event_priv = ctx;
168     }
169   else
170     {
171       /* Use user event loop.  */
172       io_cbs.add = _gpgme_wait_user_add_io_cb;
173       io_cbs.add_priv = ctx;
174       io_cbs.remove = _gpgme_wait_user_remove_io_cb;
175       io_cbs.event = _gpgme_wait_user_event_cb;
176       io_cbs.event_priv = ctx;
177     }
178   _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs);
179   return err;
180 }
181
182 \f
183 /* Parse the INV_RECP or INV-SNDR status line in ARGS and return the
184    result in KEY.  */
185 gpgme_error_t
186 _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
187 {
188   gpgme_invalid_key_t inv_key;
189   char *tail;
190   long int reason;
191
192   inv_key = malloc (sizeof (*inv_key));
193   if (!inv_key)
194     return gpg_error_from_errno (errno);
195   inv_key->next = NULL;
196   gpg_err_set_errno (0);
197   reason = strtol (args, &tail, 0);
198   if (errno || args == tail || (*tail && *tail != ' '))
199     {
200       /* The crypto backend does not behave.  */
201       free (inv_key);
202       return gpg_error (GPG_ERR_INV_ENGINE);
203     }
204
205   switch (reason)
206     {
207     default:
208     case 0:
209       inv_key->reason = gpg_error (GPG_ERR_GENERAL);
210       break;
211
212     case 1:
213       inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY);
214       break;
215
216     case 2:
217       inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
218       break;
219
220     case 3:
221       inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
222       break;
223
224     case 4:
225       inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED);
226       break;
227
228     case 5:
229       inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED);
230       break;
231
232     case 6:
233       inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN);
234       break;
235
236     case 7:
237       inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD);
238       break;
239
240     case 8:
241       inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH);
242       break;
243
244     case 9:
245       inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY);
246       break;
247
248     case 10:
249       inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED);
250       break;
251
252     case 11:
253       inv_key->reason = gpg_error (GPG_ERR_MISSING_CERT);
254       break;
255
256     case 12:
257       inv_key->reason = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
258       break;
259     }
260
261   while (*tail && *tail == ' ')
262     tail++;
263   if (*tail)
264     {
265       inv_key->fpr = strdup (tail);
266       if (!inv_key->fpr)
267         {
268           int saved_errno = errno;
269           free (inv_key);
270           return gpg_error_from_errno (saved_errno);
271         }
272     }
273   else
274     inv_key->fpr = NULL;
275
276   *key = inv_key;
277   return 0;
278 }
279
280
281 /* Parse the PLAINTEXT status line in ARGS and return the result in
282    FILENAMEP.  */
283 gpgme_error_t
284 _gpgme_parse_plaintext (char *args, char **filenamep)
285 {
286   char *tail;
287
288   while (*args == ' ')
289     args++;
290   if (*args == '\0')
291     return 0;
292
293   /* First argument is file type.  */
294   while (*args != ' ' && *args != '\0')
295     args++;
296   while (*args == ' ')
297     args++;
298   if (*args == '\0')
299     return 0;
300
301   /* Second argument is the timestamp.  */
302   while (*args != ' ' && *args != '\0')
303     args++;
304   while (*args == ' ')
305     args++;
306   if (*args == '\0')
307     return 0;
308
309   tail = args;
310   while (*tail != ' ' && *tail != '\0')
311     tail++;
312   *tail = '\0';
313   if (filenamep && *args != '\0')
314     {
315       char *filename = strdup (args);
316       if (!filename)
317         return gpg_error_from_syserror ();
318
319       *filenamep = filename;
320     }
321   return 0;
322 }