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->new_user_ids);
164   PARSE_NEXT (result->new_sub_keys);
165   PARSE_NEXT (result->new_signatures);
166   PARSE_NEXT (result->new_revocations);
167   PARSE_NEXT (result->secret_read);
168   PARSE_NEXT (result->secret_imported);
169   PARSE_NEXT (result->secret_unchanged);
170   PARSE_NEXT (result->not_imported);
171
172   return 0;
173 }
174
175
176 static GpgmeError
177 import_status_handler (void *priv, GpgmeStatusCode code, char *args)
178 {
179   GpgmeCtx ctx = (GpgmeCtx) priv;
180   GpgmeError err;
181   op_data_t opd;
182
183   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd,
184                                -1, NULL);
185   if (err)
186     return err;
187
188   switch (code)
189     {
190     case GPGME_STATUS_IMPORT_OK:
191     case GPGME_STATUS_IMPORT_PROBLEM:
192       err = parse_import (args, opd->lastp,
193                           code == GPGME_STATUS_IMPORT_OK ? 0 : 1);
194       if (err)
195         return err;
196
197       opd->lastp = &(*opd->lastp)->next;
198       break;
199
200     case GPGME_STATUS_IMPORT_RES:
201       err = parse_import_res (args, &opd->result);
202       break;
203
204     default:
205       break;
206     }
207   return 0;
208 }
209
210
211 static GpgmeError
212 _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
213 {
214   GpgmeError err;
215   op_data_t opd;
216
217   err = _gpgme_op_reset (ctx, synchronous);
218   if (err)
219     return err;
220
221   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd,
222                                sizeof (*opd), release_op_data);
223   if (err)
224     return err;
225   opd->lastp = &opd->result.imports;
226
227   if (!keydata)
228     return GPGME_No_Data;
229
230   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
231
232   return _gpgme_engine_op_import (ctx->engine, keydata);
233 }
234
235
236 GpgmeError
237 gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
238 {
239   return _gpgme_op_import_start (ctx, 0, keydata);
240 }
241
242
243 /* Import the key in KEYDATA into the keyring.  */
244 GpgmeError
245 gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)
246 {
247   GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);
248   if (!err)
249     err = _gpgme_wait_one (ctx);
250   return err;
251 }
252
253
254 GpgmeError
255 gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr)
256 {
257   GpgmeError err = gpgme_op_import (ctx, keydata);
258   if (!err && nr)
259     {
260       GpgmeImportResult result = gpgme_op_import_result (ctx);
261       *nr = result->considered;
262     }
263   return err;
264 }