40ae932b0ee21447e423435c9975196eca246409
[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
26 #include "context.h"
27 #include "ops.h"
28
29
30 struct decrypt_result
31 {
32   int okay;
33   int failed;
34 };
35 typedef struct decrypt_result *DecryptResult;
36
37
38 /* Check whether STRING starts with TOKEN and return true in this
39    case.  This is case insensitive.  If NEXT is not NULL return the
40    number of bytes to be added to STRING to get to the next token; a
41    returned value of 0 indicates end of line. 
42    Fixme: Duplicated from verify.c.  */
43 static int 
44 is_token (const char *string, const char *token, size_t *next)
45 {
46   size_t n = 0;
47
48   for (;*string && *token && *string == *token; string++, token++, n++)
49     ;
50   if (*token || (*string != ' ' && !*string))
51     return 0;
52   if (next)
53     {
54       for (; *string == ' '; string++, n++)
55         ;
56       *next = n;
57     }
58   return 1;
59 }
60
61
62 static int
63 skip_token (const char *string, size_t *next)
64 {
65   size_t n = 0;
66
67   for (;*string && *string != ' '; string++, n++)
68     ;
69   for (;*string == ' '; string++, n++)
70     ;
71   if (!*string)
72     return 0;
73   if (next)
74     *next = n;
75   return 1;
76 }
77
78
79 GpgmeError
80 _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
81 {
82   DecryptResult result;
83   GpgmeError err = 0;
84   size_t n;
85
86   err = _gpgme_passphrase_status_handler (ctx, code, args);
87   if (err)
88     return err;
89
90   switch (code)
91     {
92     case GPGME_STATUS_EOF:
93       err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &result,
94                                    -1, NULL);
95       if (!err)
96         {
97           if (result && result->failed)
98             err = GPGME_Decryption_Failed;
99           else if (!result || !result->okay)
100             err = GPGME_No_Data;
101         }
102       break;
103
104     case GPGME_STATUS_DECRYPTION_OKAY:
105       err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &result,
106                                    sizeof (*result), NULL);
107       if (!err)
108         result->okay = 1;
109       break;
110
111     case GPGME_STATUS_DECRYPTION_FAILED:
112       err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, (void **) &result,
113                                    sizeof (*result), NULL);
114       if (!err)
115         result->failed = 1;
116       break;
117
118     case GPGME_STATUS_ERROR:
119       if (is_token (args, "decrypt.algorithm", &n) && n)
120         {
121           args += n;
122           if (is_token (args, "Unsupported_Algorithm", &n))
123             {
124               GpgmeData dh;
125
126               args += n;
127               /* Fixme: This won't work when used with decrypt+verify */
128               if (!gpgme_data_new (&dh))
129                 {
130                   _gpgme_data_append_string (dh,
131                                              "<GnupgOperationInfo>\n"
132                                              " <decryption>\n"
133                                              "  <error>\n"
134                                              "   <unsupportedAlgorithm>");
135                   if (skip_token (args, &n))
136                     {
137                       int c = args[n];
138                       args[n] = 0;
139                       _gpgme_data_append_percentstring_for_xml (dh, args);
140                       args[n] = c;
141                     }
142                   else
143                     _gpgme_data_append_percentstring_for_xml (dh, args);
144                   
145                   _gpgme_data_append_string (dh,
146                                              "</unsupportedAlgorithm>\n"
147                                              "  </error>\n"
148                                              " </decryption>\n"
149                                              "</GnupgOperationInfo>\n");
150                   _gpgme_set_op_info (ctx, dh);
151                 }
152             }
153         }
154       break;
155         
156     default:
157       break;
158     }
159
160   return err;
161 }
162
163
164 GpgmeError
165 _gpgme_decrypt_start (GpgmeCtx ctx, int synchronous,
166                       GpgmeData ciph, GpgmeData plain, void *status_handler)
167 {
168   GpgmeError err = 0;
169
170   err = _gpgme_op_reset (ctx, synchronous);
171   if (err)
172     goto leave;
173
174   /* Check the supplied data.  */
175   if (!ciph)
176     {
177       err = GPGME_No_Data;
178       goto leave;
179     }
180   if (!plain)
181     {
182       err = GPGME_Invalid_Value;
183       goto leave;
184     }
185
186   err = _gpgme_passphrase_start (ctx);
187   if (err)
188     goto leave;
189
190   _gpgme_engine_set_status_handler (ctx->engine, status_handler, ctx);
191   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
192
193   err = _gpgme_engine_op_decrypt (ctx->engine, ciph, plain);
194
195  leave:
196   if (err)
197     {
198       _gpgme_engine_release (ctx->engine);
199       ctx->engine = NULL;
200     }
201   return err;
202 }
203
204
205 GpgmeError
206 gpgme_op_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain)
207 {
208   return _gpgme_decrypt_start (ctx, 0, ciph, plain,
209                                _gpgme_decrypt_status_handler);
210 }
211
212
213 /**
214  * gpgme_op_decrypt:
215  * @ctx: The context
216  * @in: ciphertext input
217  * @out: plaintext output
218  * 
219  * This function decrypts @in to @out.
220  * Other parameters are take from the context @ctx.
221  * The function does wait for the result.
222  * 
223  * Return value:  0 on success or an errorcode. 
224  **/
225 GpgmeError
226 gpgme_op_decrypt (GpgmeCtx ctx, GpgmeData in, GpgmeData out)
227 {
228   GpgmeError err = _gpgme_decrypt_start (ctx, 1, in, out,
229                                          _gpgme_decrypt_status_handler);
230   if (!err)
231       err = _gpgme_wait_one (ctx);
232   return err;
233 }