2003-05-18 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
27 #include "gpgme.h"
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32 \f
33 typedef struct
34 {
35   struct _gpgme_op_decrypt_result result;
36
37   int okay;
38   int failed;
39 } *op_data_t;
40
41
42 static void
43 release_op_data (void *hook)
44 {
45   op_data_t opd = (op_data_t) hook;
46
47   if (opd->result.unsupported_algorithm)
48     free (opd->result.unsupported_algorithm);
49 }
50
51
52 gpgme_decrypt_result_t
53 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
54 {
55   op_data_t opd;
56   gpgme_error_t err;
57
58   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &opd, -1, NULL);
59   if (err || !opd)
60     return NULL;
61
62   return &opd->result;
63 }
64
65 \f
66 gpgme_error_t
67 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
68 {
69   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
70   gpgme_error_t err;
71   op_data_t opd;
72
73   err = _gpgme_passphrase_status_handler (priv, code, args);
74   if (err)
75     return err;
76
77   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &opd, -1, NULL);
78   if (err)
79     return err;
80
81   switch (code)
82     {
83     case GPGME_STATUS_EOF:
84       if (opd->failed)
85         return GPGME_Decryption_Failed;
86       else if (!opd->okay)
87         return GPGME_No_Data;
88       break;
89
90     case GPGME_STATUS_DECRYPTION_OKAY:
91       opd->okay = 1;
92       break;
93
94     case GPGME_STATUS_DECRYPTION_FAILED:
95       opd->failed = 1;
96       break;
97
98     case GPGME_STATUS_ERROR:
99       {
100         const char d_alg[] = "decrypt.algorithm";
101         const char u_alg[] = "Unsupported_Algorithm";
102         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
103           {
104             args += sizeof (d_alg);
105             while (*args == ' ')
106               args++;
107
108             if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
109               {
110                 char *end;
111
112                 args += sizeof (u_alg);
113                 while (*args == ' ')
114                   args++;
115
116                 end = strchr (args, ' ');
117                 if (end)
118                   *end = '\0';
119
120                 if (!(*args == '?' && *(args + 1) == '\0'))
121                   {
122                     opd->result.unsupported_algorithm = strdup (args);
123                     if (!opd->result.unsupported_algorithm)
124                       return GPGME_Out_Of_Core;
125                   }
126               }
127           }
128       }
129       break;
130         
131     default:
132       break;
133     }
134
135   return 0;
136 }
137
138
139 gpgme_error_t
140 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
141 {
142   op_data_t opd;
143
144   return _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &opd,
145                                 sizeof (*opd), release_op_data);
146 }
147
148
149 static gpgme_error_t
150 decrypt_start (gpgme_ctx_t ctx, int synchronous,
151                       gpgme_data_t cipher, gpgme_data_t plain)
152 {
153   gpgme_error_t err;
154
155   err = _gpgme_op_reset (ctx, synchronous);
156   if (err)
157     return err;
158
159   err = _gpgme_op_decrypt_init_result (ctx);
160   if (err)
161     return err;
162
163   if (!cipher)
164     return GPGME_No_Data;
165   if (!plain)
166     return GPGME_Invalid_Value;
167
168   if (err)
169     return err;
170
171   if (ctx->passphrase_cb)
172     {
173       err = _gpgme_engine_set_command_handler (ctx->engine,
174                                                _gpgme_passphrase_command_handler,
175                                                ctx, NULL);
176       if (err)
177         return err;
178     }
179
180   _gpgme_engine_set_status_handler (ctx->engine,
181                                     _gpgme_decrypt_status_handler, ctx);
182
183   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
184 }
185
186
187 gpgme_error_t
188 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
189 {
190   return decrypt_start (ctx, 0, cipher, plain);
191 }
192
193
194 /* Decrypt ciphertext CIPHER within CTX and store the resulting
195    plaintext in PLAIN.  */
196 gpgme_error_t
197 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
198 {
199   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
200   if (!err)
201     err = _gpgme_wait_one (ctx);
202   return err;
203 }