gpgme/
[gpgme.git] / gpgme / decrypt.c
1 /* decrypt.c -  decrypt functions
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify
8  * it 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,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32 struct decrypt_result_s
33 {
34   int okay;
35   int failed;
36 };
37
38 void
39 _gpgme_release_decrypt_result (DecryptResult result)
40 {
41   if (!result)
42     return;
43   xfree (result);
44 }
45
46 static GpgmeError
47 create_result_struct (GpgmeCtx ctx)
48 {
49   assert (!ctx->result.decrypt);
50   ctx->result.decrypt = xtrycalloc (1, sizeof *ctx->result.decrypt);
51   if (!ctx->result.decrypt)
52     return mk_error (Out_Of_Core);
53   return 0;    
54 }
55
56 void
57 _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
58 {
59   _gpgme_passphrase_status_handler (ctx, code, args);
60
61   if (ctx->out_of_core)
62     return;
63
64   if (! ctx->result.decrypt)
65     {
66       if (create_result_struct (ctx))
67         {
68           ctx->out_of_core = 1;
69           return;
70         }
71     }
72
73   switch (code)
74     {
75     case STATUS_EOF:
76       break;
77
78     case STATUS_DECRYPTION_OKAY:
79       ctx->result.decrypt->okay = 1;
80       break;
81
82     case STATUS_DECRYPTION_FAILED:
83       ctx->result.decrypt->failed = 1;
84       break;
85         
86     default:
87       /* Ignore all other codes.  */
88       break;
89     }
90 }
91
92 GpgmeError
93 _gpgme_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain,
94                       void *status_handler)
95 {
96   GpgmeError err = 0;
97   int i;
98
99   fail_on_pending_request (ctx);
100   ctx->pending = 1;
101
102   _gpgme_release_result (ctx);
103   ctx->out_of_core = 0;
104
105   /* Do some checks.  */
106  
107   /* Create a process object.  */
108   _gpgme_gpg_release (ctx->gpg);
109   err = _gpgme_gpg_new (&ctx->gpg);
110   if (err)
111     goto leave;
112
113   _gpgme_gpg_set_status_handler (ctx->gpg, status_handler, ctx);
114
115   err = _gpgme_passphrase_start (ctx);
116   if (err)
117     goto leave;
118
119   /* Build the commandline.  */
120   _gpgme_gpg_add_arg (ctx->gpg, "--decrypt");
121   for (i = 0; i < ctx->verbosity; i++)
122     _gpgme_gpg_add_arg (ctx->gpg, "--verbose");
123
124   /* Check the supplied data.  */
125   if (!ciph || gpgme_data_get_type (ciph) == GPGME_DATA_TYPE_NONE)
126     {
127       err = mk_error (No_Data);
128       goto leave;
129     }
130   _gpgme_data_set_mode (ciph, GPGME_DATA_MODE_OUT);
131
132   if (gpgme_data_get_type (plain) != GPGME_DATA_TYPE_NONE)
133     {
134       err = mk_error (Invalid_Value);
135       goto leave;
136     }
137   _gpgme_data_set_mode (plain, GPGME_DATA_MODE_IN);
138
139   /* Tell the gpg object about the data.  */
140   _gpgme_gpg_add_arg (ctx->gpg, "--output");
141   _gpgme_gpg_add_arg (ctx->gpg, "-");
142   _gpgme_gpg_add_data (ctx->gpg, plain, 1);
143   _gpgme_gpg_add_data (ctx->gpg, ciph, 0);
144
145   /* And kick off the process.  */
146   err = _gpgme_gpg_spawn (ctx->gpg, ctx);
147
148  leave:
149   if (err)
150     {
151       ctx->pending = 0; 
152       _gpgme_gpg_release (ctx->gpg);
153       ctx->gpg = NULL;
154     }
155   return err;
156 }
157
158 GpgmeError
159 gpgme_op_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain)
160 {
161   return _gpgme_decrypt_start (ctx, ciph, plain,
162                                _gpgme_decrypt_status_handler);
163 }
164
165 GpgmeError
166 _gpgme_decrypt_result (GpgmeCtx ctx)
167 {
168   GpgmeError err = 0;
169
170   if (!ctx->result.decrypt)
171     err = mk_error (General_Error);
172   else if (ctx->out_of_core)
173     err = mk_error (Out_Of_Core);
174   else
175     {
176       err = _gpgme_passphrase_result (ctx);
177       if (! err)
178         {
179           if (ctx->result.decrypt->failed)
180             err = mk_error (Decryption_Failed);
181           else if (!ctx->result.decrypt->okay)
182             err = mk_error (No_Data);
183         }
184     }
185   return err;
186 }
187
188 /**
189  * gpgme_op_decrypt:
190  * @ctx: The context
191  * @in: ciphertext input
192  * @out: plaintext output
193  * 
194  * This function decrypts @in to @out.
195  * Other parameters are take from the context @ctx.
196  * The function does wait for the result.
197  * 
198  * Return value:  0 on success or an errorcode. 
199  **/
200 GpgmeError
201 gpgme_op_decrypt (GpgmeCtx ctx, GpgmeData in, GpgmeData out)
202 {
203   GpgmeError err = gpgme_op_decrypt_start (ctx, in, out);
204   if (!err)
205     {
206       gpgme_wait (ctx, 1);
207       err = _gpgme_decrypt_result (ctx);
208       ctx->pending = 0;
209     }
210   return err;
211 }