* verify.c (_gpgme_verify_status_handler): Ignore the error status
[gpgme.git] / gpgme / decrypt.c
1 /* decrypt.c - Decrypt function.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
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 2 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    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include "gpgme.h"
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32
33 \f
34 typedef struct
35 {
36   struct _gpgme_op_decrypt_result result;
37
38   int okay;
39   int failed;
40 } *op_data_t;
41
42
43 static void
44 release_op_data (void *hook)
45 {
46   op_data_t opd = (op_data_t) hook;
47
48   if (opd->result.unsupported_algorithm)
49     free (opd->result.unsupported_algorithm);
50 }
51
52
53 gpgme_decrypt_result_t
54 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
55 {
56   void *hook;
57   op_data_t opd;
58   gpgme_error_t err;
59
60   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
61   opd = hook;
62   if (err || !opd)
63     return NULL;
64
65   return &opd->result;
66 }
67
68 \f
69 gpgme_error_t
70 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
71                                char *args)
72 {
73   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
74   gpgme_error_t err;
75   void *hook;
76   op_data_t opd;
77
78   err = _gpgme_passphrase_status_handler (priv, code, args);
79   if (err)
80     return err;
81
82   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
83   opd = hook;
84   if (err)
85     return err;
86
87   switch (code)
88     {
89     case GPGME_STATUS_EOF:
90       /* FIXME: These error values should probably be attributed to
91          the underlying crypto engine (as error source).  */
92       if (opd->failed)
93         return gpg_error (GPG_ERR_DECRYPT_FAILED);
94       else if (!opd->okay)
95         return gpg_error (GPG_ERR_NO_DATA);
96       break;
97
98     case GPGME_STATUS_DECRYPTION_OKAY:
99       opd->okay = 1;
100       break;
101
102     case GPGME_STATUS_DECRYPTION_FAILED:
103       opd->failed = 1;
104       break;
105
106     case GPGME_STATUS_ERROR:
107       /* Note that this is an informational status code which should
108          not lead to an erro retunr unless it is something not related
109          to the backend. */
110       {
111         const char d_alg[] = "decrypt.algorithm";
112         const char u_alg[] = "Unsupported_Algorithm";
113         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
114           {
115             args += sizeof (d_alg);
116             while (*args == ' ')
117               args++;
118
119             if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
120               {
121                 char *end;
122
123                 args += sizeof (u_alg);
124                 while (*args == ' ')
125                   args++;
126
127                 end = strchr (args, ' ');
128                 if (end)
129                   *end = '\0';
130
131                 if (!(*args == '?' && *(args + 1) == '\0'))
132                   {
133                     opd->result.unsupported_algorithm = strdup (args);
134                     if (!opd->result.unsupported_algorithm)
135                       return gpg_error_from_errno (errno);
136                   }
137               }
138           }
139       }
140       break;
141         
142     default:
143       break;
144     }
145
146   return 0;
147 }
148
149
150 static gpgme_error_t
151 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
152 {
153   gpgme_error_t err;
154
155   err = _gpgme_progress_status_handler (priv, code, args);
156   if (!err)
157     err = _gpgme_decrypt_status_handler (priv, code, args);
158   return err;
159 }
160
161
162 gpgme_error_t
163 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
164 {
165   void *hook;
166   op_data_t opd;
167
168   return _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
169                                 sizeof (*opd), release_op_data);
170 }
171
172
173 static gpgme_error_t
174 decrypt_start (gpgme_ctx_t ctx, int synchronous,
175                       gpgme_data_t cipher, gpgme_data_t plain)
176 {
177   gpgme_error_t err;
178
179   err = _gpgme_op_reset (ctx, synchronous);
180   if (err)
181     return err;
182
183   err = _gpgme_op_decrypt_init_result (ctx);
184   if (err)
185     return err;
186
187   if (!cipher)
188     return gpg_error (GPG_ERR_NO_DATA);
189   if (!plain)
190     return gpg_error (GPG_ERR_INV_VALUE);
191
192   if (err)
193     return err;
194
195   if (ctx->passphrase_cb)
196     {
197       err = _gpgme_engine_set_command_handler
198         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
199       if (err)
200         return err;
201     }
202
203   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
204
205   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
206 }
207
208
209 gpgme_error_t
210 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
211                         gpgme_data_t plain)
212 {
213   return decrypt_start (ctx, 0, cipher, plain);
214 }
215
216
217 /* Decrypt ciphertext CIPHER within CTX and store the resulting
218    plaintext in PLAIN.  */
219 gpgme_error_t
220 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
221 {
222   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
223   if (!err)
224     err = _gpgme_wait_one (ctx);
225   return err;
226 }