doc/
[gpgme.git] / gpgme / import.c
1 /* import.c - Import a key.
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 <errno.h>
26 #include <string.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_import_result result;
36
37   /* A pointer to the next pointer of the last import status in the
38      list.  This makes appending new imports painless while preserving
39      the order.  */
40   GpgmeImportStatus *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   GpgmeImportStatus import = opd->result.imports;
49
50   while (import)
51     {
52       GpgmeImportStatus next = import->next;
53       free (import->fpr);
54       free (import);
55       import = next;
56     }
57 }
58
59
60 GpgmeImportResult
61 gpgme_op_import_result (GpgmeCtx ctx)
62 {
63   op_data_t opd;
64   GpgmeError err;
65
66   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd, -1, NULL);
67   if (err || !opd)
68     return NULL;
69
70   return &opd->result;
71 }
72
73 \f
74 static GpgmeError
75 parse_import (char *args, GpgmeImportStatus *import_status, int problem)
76 {
77   GpgmeImportStatus import;
78   char *tail;
79   long int nr;
80
81   import = malloc (sizeof (*import));
82   if (!import)
83     return GPGME_Out_Of_Core;
84   import->next = NULL;
85
86   errno = 0;
87   nr = strtol (args, &tail, 0);
88   if (errno || args == tail || *tail != ' ')
89     {
90       /* The crypto backend does not behave.  */
91       free (import);
92       return GPGME_General_Error;
93     }
94   args = tail;
95
96   if (problem)
97     {
98       switch (nr)
99         {
100         case 0:
101         case 4:
102         default:
103           import->result = GPGME_Unknown_Reason;
104           break;
105
106         case 1:
107           import->result = GPGME_Invalid_Key;
108           break;
109
110         case 2:
111           import->result = GPGME_Issuer_Missing;
112           break;
113
114         case 3:
115           import->result = GPGME_Chain_Too_Long;
116           break;
117         }
118       import->status = 0;
119     }
120   else
121     {
122       import->result = GPGME_No_Error;
123       import->status = nr;
124     }
125
126   while (*args == ' ')
127     args++;
128   tail = strchr (args, ' ');
129   if (tail)
130     *tail = '\0';
131
132   import->fpr = strdup (args);
133   if (!import->fpr)
134     {
135       free (import);
136       return GPGME_Out_Of_Core;
137     }
138
139   *import_status = import;
140   return 0;
141 }
142
143
144
145 GpgmeError
146 parse_import_res (char *args, GpgmeImportResult result)
147 {
148   char *tail;
149
150   errno = 0;
151
152 #define PARSE_NEXT(x)                                   \
153   (x) = strtol (args, &tail, 0);                        \
154   if (errno || args == tail || *tail != ' ')            \
155     /* The crypto backend does not behave.  */          \
156     return GPGME_General_Error;                         \
157   args = tail;
158
159   PARSE_NEXT (result->considered);
160   PARSE_NEXT (result->no_user_id);
161   PARSE_NEXT (result->imported);
162   PARSE_NEXT (result->imported_rsa);
163   PARSE_NEXT (result->unchanged);
164   PARSE_NEXT (result->new_user_ids);
165   PARSE_NEXT (result->new_sub_keys);
166   PARSE_NEXT (result->new_signatures);
167   PARSE_NEXT (result->new_revocations);
168   PARSE_NEXT (result->secret_read);
169   PARSE_NEXT (result->secret_imported);
170   PARSE_NEXT (result->secret_unchanged);
171   PARSE_NEXT (result->not_imported);
172
173   return 0;
174 }
175
176
177 static GpgmeError
178 import_status_handler (void *priv, GpgmeStatusCode code, char *args)
179 {
180   GpgmeCtx ctx = (GpgmeCtx) priv;
181   GpgmeError err;
182   op_data_t opd;
183
184   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd,
185                                -1, NULL);
186   if (err)
187     return err;
188
189   switch (code)
190     {
191     case GPGME_STATUS_IMPORT_OK:
192     case GPGME_STATUS_IMPORT_PROBLEM:
193       err = parse_import (args, opd->lastp,
194                           code == GPGME_STATUS_IMPORT_OK ? 0 : 1);
195       if (err)
196         return err;
197
198       opd->lastp = &(*opd->lastp)->next;
199       break;
200
201     case GPGME_STATUS_IMPORT_RES:
202       err = parse_import_res (args, &opd->result);
203       break;
204
205     default:
206       break;
207     }
208   return 0;
209 }
210
211
212 static GpgmeError
213 _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
214 {
215   GpgmeError err;
216   op_data_t opd;
217
218   err = _gpgme_op_reset (ctx, synchronous);
219   if (err)
220     return err;
221
222   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd,
223                                sizeof (*opd), release_op_data);
224   if (err)
225     return err;
226   opd->lastp = &opd->result.imports;
227
228   if (!keydata)
229     return GPGME_No_Data;
230
231   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
232
233   return _gpgme_engine_op_import (ctx->engine, keydata);
234 }
235
236
237 GpgmeError
238 gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
239 {
240   return _gpgme_op_import_start (ctx, 0, keydata);
241 }
242
243
244 /* Import the key in KEYDATA into the keyring.  */
245 GpgmeError
246 gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)
247 {
248   GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);
249   if (!err)
250     err = _gpgme_wait_one (ctx);
251   return err;
252 }
253
254
255 GpgmeError
256 gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr)
257 {
258   GpgmeError err = gpgme_op_import (ctx, keydata);
259   if (!err && nr)
260     {
261       GpgmeImportResult result = gpgme_op_import_result (ctx);
262       *nr = result->considered;
263     }
264   return err;
265 }