doc/
[gpgme.git] / gpgme / 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       invalid_recipient = next;
57     }
58 }
59
60
61 gpgme_encrypt_result_t
62 gpgme_op_encrypt_result (gpgme_ctx_t ctx)
63 {
64   void *hook;
65   op_data_t opd;
66   gpgme_error_t err;
67
68   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
69   opd = hook;
70
71   if (err || !opd)
72     return NULL;
73
74   return &opd->result;
75 }
76
77 \f
78 gpgme_error_t
79 _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
80                                char *args)
81 {
82   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
83   gpgme_error_t err;
84   void *hook;
85   op_data_t opd;
86
87   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
88   opd = hook;
89   if (err)
90     return err;
91
92   switch (code)
93     {
94     case GPGME_STATUS_EOF:
95       if (opd->result.invalid_recipients)
96         return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
97       break;
98
99     case GPGME_STATUS_INV_RECP:
100       err = _gpgme_parse_inv_recp (args, opd->lastp);
101       if (err)
102         return err;
103
104       opd->lastp = &(*opd->lastp)->next;
105       break;
106
107     case GPGME_STATUS_NO_RECP:
108       /* Should not happen, because we require at least one recipient.  */
109       return gpg_error (GPG_ERR_GENERAL);
110
111     default:
112       break;
113     }
114   return 0;
115 }
116
117
118 static gpgme_error_t
119 encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
120 {
121   gpgme_error_t err;
122
123   err = _gpgme_progress_status_handler (priv, code, args);
124   if (!err)
125     err = _gpgme_passphrase_status_handler (priv, code, args);
126   return err;
127 }
128
129
130 static gpgme_error_t
131 encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
132 {
133   return _gpgme_progress_status_handler (priv, code, args)
134     || _gpgme_encrypt_status_handler (priv, code, args);
135 }
136
137
138 gpgme_error_t
139 _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
140 {
141   gpgme_error_t err;
142   void *hook;
143   op_data_t opd;
144
145   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, sizeof (*opd),
146                                release_op_data);
147   opd = hook;
148   if (err)
149     return err;
150
151   opd->lastp = &opd->result.invalid_recipients;
152   return 0;
153 }
154
155
156 static gpgme_error_t
157 encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
158                gpgme_encrypt_flags_t flags,
159                gpgme_data_t plain, gpgme_data_t cipher)
160 {
161   gpgme_error_t err;
162   int symmetric = 0;
163
164   err = _gpgme_op_reset (ctx, synchronous);
165   if (err)
166     return err;
167
168   err = _gpgme_op_encrypt_init_result (ctx);
169   if (err)
170     return err;
171
172   if (!recp)
173     symmetric = 1;
174
175   if (!plain)
176     return gpg_error (GPG_ERR_NO_DATA);
177   if (!cipher)
178     return gpg_error (GPG_ERR_INV_VALUE);
179   if (recp && ! *recp)
180     return gpg_error (GPG_ERR_INV_VALUE);
181
182   if (symmetric && ctx->passphrase_cb)
183     {
184       /* Symmetric encryption requires a passphrase.  */
185       err = _gpgme_engine_set_command_handler
186         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
187       if (err)
188         return err;
189     }
190
191   _gpgme_engine_set_status_handler (ctx->engine,
192                                     symmetric
193                                     ? encrypt_sym_status_handler
194                                     : encrypt_status_handler,
195                                     ctx);
196
197   return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher,
198                                    ctx->use_armor);
199 }
200
201
202 gpgme_error_t
203 gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
204                         gpgme_encrypt_flags_t flags,
205                         gpgme_data_t plain, gpgme_data_t cipher)
206 {
207   return encrypt_start (ctx, 0, recp, flags, plain, cipher);
208 }
209
210
211 /* Encrypt plaintext PLAIN within CTX for the recipients RECP and
212    store the resulting ciphertext in CIPHER.  */
213 gpgme_error_t
214 gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
215                   gpgme_encrypt_flags_t flags,
216                   gpgme_data_t plain, gpgme_data_t cipher)
217 {
218   gpgme_error_t err = encrypt_start (ctx, 1, recp, flags, plain, cipher);
219   if (!err)
220     err = _gpgme_wait_one (ctx);
221   return err;
222 }