7679d74779c7ff09af6c73b87f1584ed22c66fde
[gpgme.git] / gpgme / encrypt.c
1 /* encrypt.c - Encrypt functions.
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 <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32 #include "wait.h"
33
34 #define SKIP_TOKEN_OR_RETURN(a) do { \
35     while (*(a) && *(a) != ' ') (a)++; \
36     while (*(a) == ' ') (a)++; \
37     if (!*(a)) \
38         return; /* oops */ \
39 } while (0)
40
41 struct encrypt_result
42 {
43   int no_valid_recipients;
44   int invalid_recipients;
45   GpgmeData xmlinfo;
46 };
47 typedef struct encrypt_result *EncryptResult;
48
49 static void
50 release_encrypt_result (void *hook)
51 {
52   EncryptResult result = (EncryptResult) hook;
53
54   gpgme_data_release (result->xmlinfo);
55 }
56
57
58 /* Parse the args and save the information in an XML structure.  With
59    args of NULL the xml structure is closed.  */
60 static void
61 append_xml_encinfo (GpgmeData *rdh, char *args)
62 {
63   GpgmeData dh;
64   char helpbuf[100];
65
66   if (!*rdh)
67     {
68       if (gpgme_data_new (rdh))
69         return; /* FIXME: We are ignoring out-of-core.  */
70       dh = *rdh;
71       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
72     }
73   else
74     {
75       dh = *rdh;
76       _gpgme_data_append_string (dh, "  </encryption>\n");
77     }
78
79   if (!args)
80     {
81       /* Just close the XML containter.  */
82       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
83       return;
84     }
85
86   _gpgme_data_append_string (dh, "  <encryption>\n"
87                              "    <error>\n"
88                              "      <invalidRecipient/>\n");
89     
90   sprintf (helpbuf, "      <reason>%d</reason>\n", atoi (args));
91   _gpgme_data_append_string (dh, helpbuf);
92   SKIP_TOKEN_OR_RETURN (args);
93
94   _gpgme_data_append_string (dh, "      <name>");
95   _gpgme_data_append_percentstring_for_xml (dh, args);
96   _gpgme_data_append_string (dh, "</name>\n"
97                              "    </error>\n");
98 }
99
100
101 GpgmeError
102 _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
103 {
104   GpgmeError err = 0;
105   EncryptResult result;
106
107   switch (code)
108     {
109     case GPGME_STATUS_EOF:
110       err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, (void **) &result,
111                                    -1, NULL);
112       if (!err)
113         {
114           if (result && result->xmlinfo)
115             {
116               append_xml_encinfo (&result->xmlinfo, NULL);
117               _gpgme_set_op_info (ctx, result->xmlinfo);
118               result->xmlinfo = NULL;
119             }
120           if (result && result->no_valid_recipients) 
121             return GPGME_No_UserID;
122           if (result && result->invalid_recipients) 
123             return GPGME_Invalid_UserID;
124         }
125       break;
126
127     case GPGME_STATUS_INV_RECP:
128       err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, (void **) &result,
129                                    sizeof (*result), release_encrypt_result);
130       if (!err)
131         {
132           result->invalid_recipients++;
133           append_xml_encinfo (&result->xmlinfo, args);
134         }
135       break;
136
137     case GPGME_STATUS_NO_RECP:
138       err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, (void **) &result,
139                                    sizeof (*result), release_encrypt_result);
140       if (!err)
141         result->no_valid_recipients = 1;
142       break;
143
144     default:
145       break;
146     }
147   return err;
148 }
149
150
151 GpgmeError
152 _gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,
153                                    char *args)
154 {
155   return _gpgme_passphrase_status_handler (ctx, code, args);
156 }
157
158
159 static GpgmeError
160 _gpgme_op_encrypt_start (GpgmeCtx ctx, int synchronous,
161                          GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph)
162 {
163   GpgmeError err = 0;
164   int symmetric = 0;
165
166   /* Do some checks.  */
167   if (!recp)
168     symmetric = 1;
169   else if (!gpgme_recipients_count (recp))
170     {
171       err = GPGME_No_UserID;
172       goto leave;
173     }
174
175   err = _gpgme_op_reset (ctx, synchronous);
176   if (err)
177     goto leave;
178
179   if (symmetric)
180     {
181       err = _gpgme_passphrase_start (ctx);
182       if (err)
183         goto leave;
184     }
185
186   _gpgme_engine_set_status_handler (ctx->engine,
187                                     symmetric
188                                     ? _gpgme_encrypt_sym_status_handler
189                                     : _gpgme_encrypt_status_handler,
190                                     ctx);
191   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
192
193   /* Check the supplied data */
194   if (!plain)
195     {
196       err = GPGME_No_Data;
197       goto leave;
198     }
199   if (!ciph)
200     {
201       err = GPGME_Invalid_Value;
202       goto leave;
203     }
204
205   err = _gpgme_engine_op_encrypt (ctx->engine, recp, plain, ciph,
206                                   ctx->use_armor);
207
208  leave:
209   if (err)
210     {
211       _gpgme_engine_release (ctx->engine);
212       ctx->engine = NULL;
213     }
214   return err;
215 }
216
217
218 GpgmeError
219 gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
220                         GpgmeData ciph)
221 {
222   return _gpgme_op_encrypt_start (ctx, 0, recp, plain, ciph);
223 }
224
225
226 /**
227  * gpgme_op_encrypt:
228  * @c: The context
229  * @recp: A set of recipients 
230  * @in: plaintext input
231  * @out: ciphertext output
232  * 
233  * This function encrypts @in to @out for all recipients from
234  * @recp.  Other parameters are take from the context @c.
235  * The function does wait for the result.
236  * 
237  * Return value:  0 on success or an errorcode. 
238  **/
239 GpgmeError
240 gpgme_op_encrypt (GpgmeCtx ctx, GpgmeRecipients recp,
241                   GpgmeData plain, GpgmeData cipher)
242 {
243   int err = _gpgme_op_encrypt_start (ctx, 1, recp, plain, cipher);
244   if (!err)
245     err = _gpgme_wait_one (ctx);
246   return err;
247 }