4744090d715eac1cf8dc63efb7edd39e68e1ad24
[gpgme.git] / src / encrypt.c
1 /* encrypt.c - Encrypt function.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004 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 Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (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    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include "gpgme.h"
30 #include "context.h"
31 #include "ops.h"
32
33 \f
34 typedef struct
35 {
36   struct _gpgme_op_encrypt_result result;
37
38   /* A pointer to the next pointer of the last invalid recipient in
39      the list.  This makes appending new invalid recipients painless
40      while preserving the order.  */
41   gpgme_invalid_key_t *lastp;
42 } *op_data_t;
43
44
45 static void
46 release_op_data (void *hook)
47 {
48   op_data_t opd = (op_data_t) hook;
49   gpgme_invalid_key_t invalid_recipient = opd->result.invalid_recipients;
50
51   while (invalid_recipient)
52     {
53       gpgme_invalid_key_t next = invalid_recipient->next;
54       if (invalid_recipient->fpr)
55         free (invalid_recipient->fpr);
56       free (invalid_recipient);
57       invalid_recipient = next;
58     }
59 }
60
61
62 gpgme_encrypt_result_t
63 gpgme_op_encrypt_result (gpgme_ctx_t ctx)
64 {
65   void *hook;
66   op_data_t opd;
67   gpgme_error_t err;
68
69   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
70   opd = hook;
71
72   if (err || !opd)
73     return NULL;
74
75   return &opd->result;
76 }
77
78 \f
79 gpgme_error_t
80 _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
81                                char *args)
82 {
83   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
84   gpgme_error_t err;
85   void *hook;
86   op_data_t opd;
87
88   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
89   opd = hook;
90   if (err)
91     return err;
92
93   switch (code)
94     {
95     case GPGME_STATUS_EOF:
96       if (opd->result.invalid_recipients)
97         return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
98       break;
99
100     case GPGME_STATUS_INV_RECP:
101       err = _gpgme_parse_inv_recp (args, opd->lastp);
102       if (err)
103         return err;
104
105       opd->lastp = &(*opd->lastp)->next;
106       break;
107
108     case GPGME_STATUS_NO_RECP:
109       /* Should not happen, because we require at least one recipient.  */
110       return gpg_error (GPG_ERR_GENERAL);
111
112     default:
113       break;
114     }
115   return 0;
116 }
117
118
119 static gpgme_error_t
120 encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
121 {
122   gpgme_error_t err;
123
124   err = _gpgme_progress_status_handler (priv, code, args);
125   if (!err)
126     err = _gpgme_passphrase_status_handler (priv, code, args);
127   return err;
128 }
129
130
131 static gpgme_error_t
132 encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
133 {
134   return _gpgme_progress_status_handler (priv, code, args)
135     || _gpgme_encrypt_status_handler (priv, code, args);
136 }
137
138
139 gpgme_error_t
140 _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
141 {
142   gpgme_error_t err;
143   void *hook;
144   op_data_t opd;
145
146   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, sizeof (*opd),
147                                release_op_data);
148   opd = hook;
149   if (err)
150     return err;
151
152   opd->lastp = &opd->result.invalid_recipients;
153   return 0;
154 }
155
156
157 static gpgme_error_t
158 encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
159                gpgme_encrypt_flags_t flags,
160                gpgme_data_t plain, gpgme_data_t cipher)
161 {
162   gpgme_error_t err;
163   int symmetric = 0;
164
165   err = _gpgme_op_reset (ctx, synchronous);
166   if (err)
167     return err;
168
169   err = _gpgme_op_encrypt_init_result (ctx);
170   if (err)
171     return err;
172
173   if (!recp)
174     symmetric = 1;
175
176   if (!plain)
177     return gpg_error (GPG_ERR_NO_DATA);
178   if (!cipher)
179     return gpg_error (GPG_ERR_INV_VALUE);
180   if (recp && ! *recp)
181     return gpg_error (GPG_ERR_INV_VALUE);
182
183   if (symmetric && ctx->passphrase_cb)
184     {
185       /* Symmetric encryption requires a passphrase.  */
186       err = _gpgme_engine_set_command_handler
187         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
188       if (err)
189         return err;
190     }
191
192   _gpgme_engine_set_status_handler (ctx->engine,
193                                     symmetric
194                                     ? encrypt_sym_status_handler
195                                     : encrypt_status_handler,
196                                     ctx);
197
198   return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher,
199                                    ctx->use_armor);
200 }
201
202
203 gpgme_error_t
204 gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
205                         gpgme_encrypt_flags_t flags,
206                         gpgme_data_t plain, gpgme_data_t cipher)
207 {
208   return encrypt_start (ctx, 0, recp, flags, plain, cipher);
209 }
210
211
212 /* Encrypt plaintext PLAIN within CTX for the recipients RECP and
213    store the resulting ciphertext in CIPHER.  */
214 gpgme_error_t
215 gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
216                   gpgme_encrypt_flags_t flags,
217                   gpgme_data_t plain, gpgme_data_t cipher)
218 {
219   gpgme_error_t err = encrypt_start (ctx, 1, recp, flags, plain, cipher);
220   if (!err)
221     err = _gpgme_wait_one (ctx);
222   return err;
223 }