Really remove file.
[gpgme.git] / gpgme / sign.c
1 /* sign.c - Signing 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_sign_result result;
36
37   /* A pointer to the next pointer of the last invalid signer in
38      the list.  This makes appending new invalid signers painless
39      while preserving the order.  */
40   GpgmeInvalidUserID *last_signer_p;
41
42   /* Likewise for signature information.  */
43   GpgmeNewSignature *last_sig_p;
44 } *op_data_t;
45
46
47 static void
48 release_op_data (void *hook)
49 {
50   op_data_t opd = (op_data_t) hook;
51   GpgmeInvalidUserID invalid_signer = opd->result.invalid_signers;
52   GpgmeNewSignature sig = opd->result.signatures;
53
54   while (invalid_signer)
55     {
56       GpgmeInvalidUserID next = invalid_signer->next;
57       free (invalid_signer->id);
58       free (invalid_signer);
59       invalid_signer = next;
60     }
61
62   while (sig)
63     {
64       GpgmeNewSignature next = sig->next;
65       free (sig->fpr);
66       free (sig);
67       sig = next;
68     }
69 }
70
71
72 GpgmeSignResult
73 gpgme_op_sign_result (GpgmeCtx ctx)
74 {
75   op_data_t opd;
76   GpgmeError err;
77
78   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd, -1, NULL);
79   if (err || !opd)
80     return NULL;
81
82   return &opd->result;
83 }
84
85 \f
86 static GpgmeError
87 parse_sig_created (char *args, GpgmeNewSignature *sigp)
88 {
89   GpgmeNewSignature sig;
90   char *tail;
91
92   sig = malloc (sizeof (*sig));
93   if (!sig)
94     return GPGME_Out_Of_Core;
95
96   sig->next = NULL;
97   switch (*args)
98     {
99     case 'S':
100       sig->type = GPGME_SIG_MODE_NORMAL;
101       break;
102
103     case 'D':
104       sig->type = GPGME_SIG_MODE_DETACH;
105       break;
106
107     case 'C':
108       sig->type = GPGME_SIG_MODE_CLEAR;
109       break;
110
111     default:
112       /* The backend engine is not behaving.  */
113       free (sig);
114       return GPGME_General_Error;
115     }
116
117   args++;
118   if (*args != ' ')
119     {
120       free (sig);
121       return GPGME_General_Error;
122     }
123
124   errno = 0;
125   sig->pubkey_algo = strtol (args, &tail, 0);
126   if (errno || args == tail || *tail != ' ')
127     {
128       /* The crypto backend does not behave.  */
129       free (sig);
130       return GPGME_General_Error;
131     }
132   args = tail;
133
134   sig->hash_algo = strtol (args, &tail, 0);
135   if (errno || args == tail || *tail != ' ')
136     {
137       /* The crypto backend does not behave.  */
138       free (sig);
139       return GPGME_General_Error;
140     }
141   args = tail;
142
143   sig->class = strtol (args, &tail, 0);
144   if (errno || args == tail || *tail != ' ')
145     {
146       /* The crypto backend does not behave.  */
147       free (sig);
148       return GPGME_General_Error;
149     }
150   args = tail;
151
152   sig->timestamp = strtol (args, &tail, 0);
153   if (errno || args == tail || *tail != ' ')
154     {
155       /* The crypto backend does not behave.  */
156       free (sig);
157       return GPGME_General_Error;
158     }
159   args = tail;
160   while (*args == ' ')
161     args++;
162
163   if (!*args)
164     {
165       /* The crypto backend does not behave.  */
166       free (sig);
167       return GPGME_General_Error;
168     }
169
170   tail = strchr (args, ' ');
171   if (tail)
172     *tail = '\0';
173
174   sig->fpr = strdup (args);
175   if (!sig->fpr)
176     {
177       free (sig);
178       return GPGME_Out_Of_Core;
179     }
180   *sigp = sig;
181   return 0;
182 }
183
184
185 GpgmeError
186 _gpgme_sign_status_handler (void *priv, GpgmeStatusCode code, char *args)
187 {
188   GpgmeCtx ctx = (GpgmeCtx) priv;
189   GpgmeError err;
190   op_data_t opd;
191
192   err = _gpgme_passphrase_status_handler (priv, code, args);
193   if (err)
194     return err;
195
196   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd, -1, NULL);
197   if (err)
198     return err;
199
200   switch (code)
201     {
202     case GPGME_STATUS_SIG_CREATED:
203       err = parse_sig_created (args, opd->last_sig_p);
204       if (err)
205         return err;
206
207       opd->last_sig_p = &(*opd->last_sig_p)->next;
208       break;
209
210     case GPGME_STATUS_INV_RECP:
211       err = _gpgme_parse_inv_userid (args, opd->last_signer_p);
212       if (err)
213         return err;
214
215       opd->last_signer_p = &(*opd->last_signer_p)->next;
216       break;
217
218     case GPGME_STATUS_EOF:
219       if (opd->result.invalid_signers)
220         return GPGME_Invalid_UserID;
221       break;
222
223     default:
224       break;
225     }
226   return err;
227 }
228
229
230 GpgmeError
231 _gpgme_op_sign_init_result (GpgmeCtx ctx)
232 {
233   GpgmeError err;
234   op_data_t opd;
235
236   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd,
237                                sizeof (*opd), release_op_data);
238   if (err)
239     return err;
240   opd->last_signer_p = &opd->result.invalid_signers;
241   opd->last_sig_p = &opd->result.signatures;
242   return 0;
243 }
244
245
246 static GpgmeError
247 sign_start (GpgmeCtx ctx, int synchronous, GpgmeData plain, GpgmeData sig,
248             GpgmeSigMode mode)
249 {
250   GpgmeError err;
251
252   err = _gpgme_op_reset (ctx, synchronous);
253   if (err)
254     return err;
255
256   err = _gpgme_op_sign_init_result (ctx);
257   if (err)
258     return err;
259
260   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
261       && mode != GPGME_SIG_MODE_CLEAR)
262     return GPGME_Invalid_Value;
263
264   if (!plain)
265     return GPGME_No_Data;
266   if (!sig)
267     return GPGME_Invalid_Value;
268
269   if (ctx->passphrase_cb)
270     {
271       err = _gpgme_engine_set_command_handler (ctx->engine,
272                                                _gpgme_passphrase_command_handler,
273                                                ctx, NULL);
274       if (err)
275         return err;
276     }
277
278   _gpgme_engine_set_status_handler (ctx->engine, _gpgme_sign_status_handler,
279                                     ctx);
280
281   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
282                                 ctx->use_textmode, ctx->include_certs,
283                                 ctx /* FIXME */);
284 }
285
286
287 /* Sign the plaintext PLAIN and store the signature in SIG.  */
288 GpgmeError
289 gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData plain, GpgmeData sig,
290                      GpgmeSigMode mode)
291 {
292   return sign_start (ctx, 0, plain, sig, mode);
293 }
294
295
296 /* Sign the plaintext PLAIN and store the signature in SIG.  */
297 GpgmeError
298 gpgme_op_sign (GpgmeCtx ctx, GpgmeData plain, GpgmeData sig, GpgmeSigMode mode)
299 {
300   GpgmeError err = sign_start (ctx, 1, plain, sig, mode);
301   if (!err)
302     err = _gpgme_wait_one (ctx);
303   return err;
304 }