a1d83101f9f7fc5eb3d5c6b4073d81b380fe4aa5
[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,
68                                char *args)
69 {
70   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
71   gpgme_error_t err;
72   op_data_t opd;
73
74   err = _gpgme_passphrase_status_handler (priv, code, args);
75   if (err)
76     return err;
77
78   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &opd, -1, NULL);
79   if (err)
80     return err;
81
82   switch (code)
83     {
84     case GPGME_STATUS_EOF:
85       if (opd->failed)
86         return GPGME_Decryption_Failed;
87       else if (!opd->okay)
88         return GPGME_No_Data;
89       break;
90
91     case GPGME_STATUS_DECRYPTION_OKAY:
92       opd->okay = 1;
93       break;
94
95     case GPGME_STATUS_DECRYPTION_FAILED:
96       opd->failed = 1;
97       break;
98
99     case GPGME_STATUS_ERROR:
100       {
101         const char d_alg[] = "decrypt.algorithm";
102         const char u_alg[] = "Unsupported_Algorithm";
103         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
104           {
105             args += sizeof (d_alg);
106             while (*args == ' ')
107               args++;
108
109             if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
110               {
111                 char *end;
112
113                 args += sizeof (u_alg);
114                 while (*args == ' ')
115                   args++;
116
117                 end = strchr (args, ' ');
118                 if (end)
119                   *end = '\0';
120
121                 if (!(*args == '?' && *(args + 1) == '\0'))
122                   {
123                     opd->result.unsupported_algorithm = strdup (args);
124                     if (!opd->result.unsupported_algorithm)
125                       return GPGME_Out_Of_Core;
126                   }
127               }
128           }
129       }
130       break;
131         
132     default:
133       break;
134     }
135
136   return 0;
137 }
138
139
140 static gpgme_error_t
141 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
142 {
143   return _gpgme_progress_status_handler (priv, code, args)
144     || _gpgme_decrypt_status_handler (priv, code, args);
145 }
146
147
148 gpgme_error_t
149 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
150 {
151   op_data_t opd;
152
153   return _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &opd,
154                                 sizeof (*opd), release_op_data);
155 }
156
157
158 static gpgme_error_t
159 decrypt_start (gpgme_ctx_t ctx, int synchronous,
160                       gpgme_data_t cipher, gpgme_data_t plain)
161 {
162   gpgme_error_t err;
163
164   err = _gpgme_op_reset (ctx, synchronous);
165   if (err)
166     return err;
167
168   err = _gpgme_op_decrypt_init_result (ctx);
169   if (err)
170     return err;
171
172   if (!cipher)
173     return GPGME_No_Data;
174   if (!plain)
175     return GPGME_Invalid_Value;
176
177   if (err)
178     return err;
179
180   if (ctx->passphrase_cb)
181     {
182       err = _gpgme_engine_set_command_handler
183         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
184       if (err)
185         return err;
186     }
187
188   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
189
190   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
191 }
192
193
194 gpgme_error_t
195 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
196                         gpgme_data_t plain)
197 {
198   return decrypt_start (ctx, 0, cipher, plain);
199 }
200
201
202 /* Decrypt ciphertext CIPHER within CTX and store the resulting
203    plaintext in PLAIN.  */
204 gpgme_error_t
205 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
206 {
207   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
208   if (!err)
209     err = _gpgme_wait_one (ctx);
210   return err;
211 }