doc/
[gpgme.git] / gpgme / import.c
1 /* import.c - Import 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 <stdlib.h>
25 #include <string.h>
26
27 #include "util.h"
28 #include "context.h"
29 #include "ops.h"
30
31 \f
32 struct import_result
33 {
34   int nr_imported;
35   int nr_considered;
36   GpgmeData xmlinfo;
37 };
38 typedef struct import_result *ImportResult;
39
40 static void
41 release_import_result (void *hook)
42 {
43   ImportResult result = (ImportResult) hook;
44
45   if (result->xmlinfo)
46     gpgme_data_release (result->xmlinfo);
47 }
48
49
50 /* Parse the args and append the information to the XML structure in
51    the data buffer.  With args of NULL the xml structure is
52    closed.  */
53 static void
54 append_xml_impinfo (GpgmeData *rdh, GpgmeStatusCode code, char *args)
55 {
56 #define MAX_IMPORTED_FIELDS 14
57   static const char *const imported_fields[MAX_IMPORTED_FIELDS]
58     = { "keyid", "username", 0 };
59   static const char *const imported_fields_x509[MAX_IMPORTED_FIELDS]
60     = { "fpr", 0 };
61   static const char *const import_res_fields[MAX_IMPORTED_FIELDS]
62     = { "count", "no_user_id", "imported", "imported_rsa",
63         "unchanged", "n_uids", "n_subk", "n_sigs", "s_sigsn_revoc",
64         "sec_read", "sec_imported", "sec_dups", "skipped_new", 0 };
65   const char *field[MAX_IMPORTED_FIELDS];
66   const char *const *field_name = 0;
67   GpgmeData dh;
68   int i;
69
70   /* Verify that we can use the args.  */
71   if (code != GPGME_STATUS_EOF)
72     {
73       if (!args)
74         return;
75
76       if (code == GPGME_STATUS_IMPORTED)
77         field_name = imported_fields;
78       else if (code == GPGME_STATUS_IMPORT_RES)
79         field_name = import_res_fields;
80       else
81         return;
82
83       for (i = 0; field_name[i]; i++)
84         {
85           field[i] = args;
86           if (field_name[i + 1])
87             {
88               args = strchr (args, ' ');
89               if (!args)
90                 return;  /* Invalid line.  */
91               *args++ = '\0';
92             }
93         }
94       
95       /* gpgsm does not print a useful user ID and uses a fingerprint
96          instead of the key ID. */
97       if (code == GPGME_STATUS_IMPORTED && field[0] && strlen (field[0]) > 16)
98         field_name = imported_fields_x509;
99     }
100
101   /* Initialize the data buffer if necessary.  */
102   if (!*rdh)
103     {
104       if (gpgme_data_new (rdh))
105         return; /* FIXME: We are ignoring out-of-core.  */
106       dh = *rdh;
107       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
108     }
109   else
110     dh = *rdh;
111     
112   if (code == GPGME_STATUS_EOF)
113     {
114       /* Just close the XML containter.  */
115       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
116     }
117   else
118     {
119       if (code == GPGME_STATUS_IMPORTED)
120         _gpgme_data_append_string (dh, "  <import>\n");
121       else if (code == GPGME_STATUS_IMPORT_RES)
122         _gpgme_data_append_string (dh, "  <importResult>\n");
123
124       for (i = 0; field_name[i]; i++)
125         {
126           _gpgme_data_append_string (dh, "    <");
127           _gpgme_data_append_string (dh, field_name[i]);
128           _gpgme_data_append_string (dh, ">");
129           _gpgme_data_append_string_for_xml (dh, field[i]);
130           _gpgme_data_append_string (dh, "</");
131           _gpgme_data_append_string (dh, field_name[i]);
132           _gpgme_data_append_string (dh, ">\n");
133         }
134
135       if (code == GPGME_STATUS_IMPORTED)
136         _gpgme_data_append_string (dh, "  </import>\n");
137       else if (code == GPGME_STATUS_IMPORT_RES)
138         _gpgme_data_append_string (dh, "  </importResult>\n");
139     }
140 }
141
142
143 static GpgmeError
144 import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
145 {
146   GpgmeError err;
147   ImportResult result;
148
149   err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &result,
150                                sizeof (*result), release_import_result);
151   if (err)
152     return err;
153
154   switch (code)
155     {
156     case GPGME_STATUS_EOF:
157       if (result->xmlinfo)
158         {
159           append_xml_impinfo (&result->xmlinfo, code, NULL);
160           _gpgme_set_op_info (ctx, result->xmlinfo);
161           result->xmlinfo = NULL;
162         }
163       /* XXX Calculate error value.  */
164       break;
165
166     case GPGME_STATUS_IMPORTED:
167       result->nr_imported++;
168       append_xml_impinfo (&result->xmlinfo, code, args);
169       break;
170
171     case GPGME_STATUS_IMPORT_RES:
172       result->nr_considered = strtol (args, 0, 0);
173       append_xml_impinfo (&result->xmlinfo, code, args);
174       break;
175
176     default:
177       break;
178     }
179   return 0;
180 }
181
182
183 static GpgmeError
184 _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
185 {
186   int err = 0;
187
188   err = _gpgme_op_reset (ctx, synchronous);
189   if (err)
190     goto leave;
191
192   /* Check the supplied data */
193   if (!keydata)
194     {
195       err = GPGME_No_Data;
196       goto leave;
197     }
198
199   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
200   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
201
202   err = _gpgme_engine_op_import (ctx->engine, keydata);
203
204  leave:
205   if (err)
206     {
207       _gpgme_engine_release (ctx->engine);
208       ctx->engine = NULL;
209     }
210   return err;
211 }
212
213
214 GpgmeError
215 gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
216 {
217   return _gpgme_op_import_start (ctx, 0, keydata);
218 }
219
220 /**
221  * gpgme_op_import:
222  * @c: Context 
223  * @keydata: Data object
224  * @nr: Will contain number of considered keys.
225  * 
226  * Import all key material from @keydata into the key database.
227  * 
228  * Return value: 0 on success or an error code.
229  **/
230 GpgmeError
231 gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr)
232 {
233   GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);
234   if (!err)
235     err = _gpgme_wait_one (ctx);
236   if (!err && nr)
237     {
238       ImportResult result;
239
240       err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &result,
241                                    -1, NULL);
242       if (result)
243         *nr = result->nr_considered;
244       else
245         *nr = 0;
246     }
247   return err;
248 }
249
250 GpgmeError
251 gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)
252 {
253   return gpgme_op_import_ext (ctx, keydata, 0);
254 }