2003-05-18 Marcus Brinkmann <marcus@g10code.de>
[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   op_data_t opd;
63   gpgme_error_t err;
64
65   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, (void **) &opd, -1, NULL);
66   if (err || !opd)
67     return NULL;
68
69   return &opd->result;
70 }
71
72 \f
73 gpgme_error_t
74 _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
75 {
76   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
77   gpgme_error_t err;
78   op_data_t opd;
79
80   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, (void **) &opd,
81                                -1, NULL);
82   if (err)
83     return err;
84
85   switch (code)
86     {
87     case GPGME_STATUS_EOF:
88       if (opd->result.invalid_recipients)
89         return GPGME_Invalid_UserID;
90       break;
91
92     case GPGME_STATUS_INV_RECP:
93       err = _gpgme_parse_inv_userid (args, opd->lastp);
94       if (err)
95         return err;
96
97       opd->lastp = &(*opd->lastp)->next;
98       break;
99
100     case GPGME_STATUS_NO_RECP:
101       /* Should not happen, because we require at least one recipient.  */
102       return GPGME_No_UserID;
103
104     default:
105       break;
106     }
107   return 0;
108 }
109
110
111 gpgme_error_t
112 _gpgme_encrypt_sym_status_handler (void *priv, gpgme_status_code_t code,
113                                    char *args)
114 {
115   return _gpgme_passphrase_status_handler (priv, code, args);
116 }
117
118
119 gpgme_error_t
120 _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
121 {
122   gpgme_error_t err;
123   op_data_t opd;
124
125   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, (void **) &opd,
126                                sizeof (*opd), release_op_data);
127   if (err)
128     return err;
129   opd->lastp = &opd->result.invalid_recipients;
130   return 0;
131 }
132
133
134 static gpgme_error_t
135 encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_recipients_t recp,
136                gpgme_data_t plain, gpgme_data_t cipher)
137 {
138   gpgme_error_t err;
139   int symmetric = 0;
140
141   err = _gpgme_op_reset (ctx, synchronous);
142   if (err)
143     return err;
144
145   err = _gpgme_op_encrypt_init_result (ctx);
146   if (err)
147     return err;
148
149   if (!recp)
150     symmetric = 1;
151   else if (gpgme_recipients_count (recp) == 0)
152     return GPGME_No_UserID;
153
154   if (!plain)
155     return GPGME_No_Data;
156   if (!cipher)
157     return GPGME_Invalid_Value;
158
159   if (symmetric && ctx->passphrase_cb)
160     {
161       /* Symmetric encryption requires a passphrase.  */
162       err = _gpgme_engine_set_command_handler (ctx->engine,
163                                                _gpgme_passphrase_command_handler,
164                                                ctx, NULL);
165       if (err)
166         return err;
167     }
168
169   _gpgme_engine_set_status_handler (ctx->engine,
170                                     symmetric
171                                     ? _gpgme_encrypt_sym_status_handler
172                                     : _gpgme_encrypt_status_handler,
173                                     ctx);
174
175   return _gpgme_engine_op_encrypt (ctx->engine, recp, plain, cipher,
176                                    ctx->use_armor);
177 }
178
179
180 gpgme_error_t
181 gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_recipients_t recp, gpgme_data_t plain,
182                         gpgme_data_t cipher)
183 {
184   return encrypt_start (ctx, 0, recp, plain, cipher);
185 }
186
187
188 /* Encrypt plaintext PLAIN within CTX for the recipients RECP and
189    store the resulting ciphertext in CIPHER.  */
190 gpgme_error_t
191 gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_recipients_t recp,
192                   gpgme_data_t plain, gpgme_data_t cipher)
193 {
194   int err = encrypt_start (ctx, 1, recp, plain, cipher);
195   if (!err)
196     err = _gpgme_wait_one (ctx);
197   return err;
198 }