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