2003-10-02 Marcus Brinkmann <marcus@g10code.de>
[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       {
108         const char d_alg[] = "decrypt.algorithm";
109         const char u_alg[] = "Unsupported_Algorithm";
110         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
111           {
112             args += sizeof (d_alg);
113             while (*args == ' ')
114               args++;
115
116             if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
117               {
118                 char *end;
119
120                 args += sizeof (u_alg);
121                 while (*args == ' ')
122                   args++;
123
124                 end = strchr (args, ' ');
125                 if (end)
126                   *end = '\0';
127
128                 if (!(*args == '?' && *(args + 1) == '\0'))
129                   {
130                     opd->result.unsupported_algorithm = strdup (args);
131                     if (!opd->result.unsupported_algorithm)
132                       return gpg_error_from_errno (errno);
133                   }
134               }
135           }
136       }
137       break;
138         
139     default:
140       break;
141     }
142
143   return 0;
144 }
145
146
147 static gpgme_error_t
148 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
149 {
150   gpgme_error_t err;
151
152   err = _gpgme_progress_status_handler (priv, code, args);
153   if (!err)
154     err = _gpgme_decrypt_status_handler (priv, code, args);
155   return err;
156 }
157
158
159 gpgme_error_t
160 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
161 {
162   void *hook;
163   op_data_t opd;
164
165   return _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
166                                 sizeof (*opd), release_op_data);
167 }
168
169
170 static gpgme_error_t
171 decrypt_start (gpgme_ctx_t ctx, int synchronous,
172                       gpgme_data_t cipher, gpgme_data_t plain)
173 {
174   gpgme_error_t err;
175
176   err = _gpgme_op_reset (ctx, synchronous);
177   if (err)
178     return err;
179
180   err = _gpgme_op_decrypt_init_result (ctx);
181   if (err)
182     return err;
183
184   if (!cipher)
185     return gpg_error (GPG_ERR_NO_DATA);
186   if (!plain)
187     return gpg_error (GPG_ERR_INV_VALUE);
188
189   if (err)
190     return err;
191
192   if (ctx->passphrase_cb)
193     {
194       err = _gpgme_engine_set_command_handler
195         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
196       if (err)
197         return err;
198     }
199
200   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
201
202   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
203 }
204
205
206 gpgme_error_t
207 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
208                         gpgme_data_t plain)
209 {
210   return decrypt_start (ctx, 0, cipher, plain);
211 }
212
213
214 /* Decrypt ciphertext CIPHER within CTX and store the resulting
215    plaintext in PLAIN.  */
216 gpgme_error_t
217 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
218 {
219   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
220   if (!err)
221     err = _gpgme_wait_one (ctx);
222   return err;
223 }