2002-11-05 Marcus Brinkmann <marcus@gnu.org>
[gpgme.git] / gpgme / import.c
1 /* import.c -  encrypt functions
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify
8  * it 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,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32
33 struct import_result_s
34 {
35   int nr_imported;
36   int nr_considered;
37   GpgmeData xmlinfo;
38 };
39
40
41 void
42 _gpgme_release_import_result (ImportResult result)
43 {
44   if (!result)
45     return;
46   gpgme_data_release (result->xmlinfo);
47   free (result);
48 }
49
50
51 /* Parse the args and append the information to the XML structure in
52    the data buffer.  With args of NULL the xml structure is
53    closed.  */
54 static void
55 append_xml_impinfo (GpgmeData *rdh, GpgmeStatusCode code, char *args)
56 {
57 #define MAX_IMPORTED_FIELDS 14
58   static const char *const imported_fields[MAX_IMPORTED_FIELDS]
59     = { "keyid", "username", 0 };
60   static const char *const imported_fields_x509[MAX_IMPORTED_FIELDS]
61     = { "fpr", 0 };
62   static const char *const import_res_fields[MAX_IMPORTED_FIELDS]
63     = { "count", "no_user_id", "imported", "imported_rsa",
64         "unchanged", "n_uids", "n_subk", "n_sigs", "s_sigsn_revoc",
65         "sec_read", "sec_imported", "sec_dups", "skipped_new", 0 };
66   const char *field[MAX_IMPORTED_FIELDS];
67   const char *const *field_name = 0;
68   GpgmeData dh;
69   int i;
70
71   /* Verify that we can use the args.  */
72   if (code != GPGME_STATUS_EOF)
73     {
74       if (!args)
75         return;
76
77       if (code == GPGME_STATUS_IMPORTED)
78         field_name = imported_fields;
79       else if (code == GPGME_STATUS_IMPORT_RES)
80         field_name = import_res_fields;
81       else
82         return;
83
84       for (i = 0; field_name[i]; i++)
85         {
86           field[i] = args;
87           if (field_name[i + 1])
88             {
89               args = strchr (args, ' ');
90               if (!args)
91                 return;  /* Invalid line.  */
92               *args++ = '\0';
93             }
94         }
95       
96       /* gpgsm does not print a useful user ID and uses a fingerprint
97          instead of the key ID. */
98       if (code == GPGME_STATUS_IMPORTED && field[0] && strlen (field[0]) > 16)
99         field_name = imported_fields_x509;
100     }
101
102   /* Initialize the data buffer if necessary.  */
103   if (!*rdh)
104     {
105       if (gpgme_data_new (rdh))
106         return; /* FIXME: We are ignoring out-of-core.  */
107       dh = *rdh;
108       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
109     }
110   else
111     dh = *rdh;
112     
113   if (code == GPGME_STATUS_EOF)
114     {
115       /* Just close the XML containter.  */
116       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
117     }
118   else
119     {
120       if (code == GPGME_STATUS_IMPORTED)
121         _gpgme_data_append_string (dh, "  <import>\n");
122       else if (code == GPGME_STATUS_IMPORT_RES)
123         _gpgme_data_append_string (dh, "  <importResult>\n");
124
125       for (i = 0; field_name[i]; i++)
126         {
127           _gpgme_data_append_string (dh, "    <");
128           _gpgme_data_append_string (dh, field_name[i]);
129           _gpgme_data_append_string (dh, ">");
130           _gpgme_data_append_string_for_xml (dh, field[i]);
131           _gpgme_data_append_string (dh, "</");
132           _gpgme_data_append_string (dh, field_name[i]);
133           _gpgme_data_append_string (dh, ">\n");
134         }
135
136       if (code == GPGME_STATUS_IMPORTED)
137         _gpgme_data_append_string (dh, "  </import>\n");
138       else if (code == GPGME_STATUS_IMPORT_RES)
139         _gpgme_data_append_string (dh, "  </importResult>\n");
140     }
141 }
142
143
144 static void
145 import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
146 {
147   if (ctx->error)
148     return;
149   test_and_allocate_result (ctx, import);
150
151   switch (code)
152     {
153     case GPGME_STATUS_EOF:
154       if (ctx->result.import->xmlinfo)
155         {
156           append_xml_impinfo (&ctx->result.import->xmlinfo, code, NULL);
157           _gpgme_set_op_info (ctx, ctx->result.import->xmlinfo);
158           ctx->result.import->xmlinfo = NULL;
159         }
160       /* XXX Calculate error value.  */
161       break;
162
163     case GPGME_STATUS_IMPORTED:
164       ctx->result.import->nr_imported++;
165       append_xml_impinfo (&ctx->result.import->xmlinfo, code, args);
166       break;
167
168     case GPGME_STATUS_IMPORT_RES:
169       ctx->result.import->nr_considered = strtol (args, 0, 0);
170       append_xml_impinfo (&ctx->result.import->xmlinfo, code, args);
171       break;
172
173     default:
174       break;
175     }
176 }
177
178
179 static GpgmeError
180 _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
181 {
182   int err = 0;
183
184   err = _gpgme_op_reset (ctx, synchronous);
185   if (err)
186     goto leave;
187
188   /* Check the supplied data */
189   if (!keydata)
190     {
191       err = mk_error (No_Data);
192       goto leave;
193     }
194
195   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
196   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
197
198   _gpgme_engine_op_import (ctx->engine, keydata);
199
200   if (!err)
201     err = _gpgme_engine_start (ctx->engine, ctx);
202
203  leave:
204   if (err)
205     {
206       ctx->pending = 0;
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       if (ctx->result.import)
239         *nr = ctx->result.import->nr_considered;
240       else
241         *nr = 0;
242     }
243   return err;
244 }
245
246 GpgmeError
247 gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)
248 {
249   return gpgme_op_import_ext (ctx, keydata, 0);
250 }
251