Fix comment indentation.
[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
32 struct import_result_s
33 {
34   int nr_imported;
35   int nr_considered;
36   GpgmeData xmlinfo;
37 };
38
39
40 void
41 _gpgme_release_import_result (ImportResult result)
42 {
43   if (!result)
44     return;
45   gpgme_data_release (result->xmlinfo);
46   free (result);
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   test_and_allocate_result (ctx, import);
147
148   switch (code)
149     {
150     case GPGME_STATUS_EOF:
151       if (ctx->result.import->xmlinfo)
152         {
153           append_xml_impinfo (&ctx->result.import->xmlinfo, code, NULL);
154           _gpgme_set_op_info (ctx, ctx->result.import->xmlinfo);
155           ctx->result.import->xmlinfo = NULL;
156         }
157       /* XXX Calculate error value.  */
158       break;
159
160     case GPGME_STATUS_IMPORTED:
161       ctx->result.import->nr_imported++;
162       append_xml_impinfo (&ctx->result.import->xmlinfo, code, args);
163       break;
164
165     case GPGME_STATUS_IMPORT_RES:
166       ctx->result.import->nr_considered = strtol (args, 0, 0);
167       append_xml_impinfo (&ctx->result.import->xmlinfo, code, args);
168       break;
169
170     default:
171       break;
172     }
173   return 0;
174 }
175
176
177 static GpgmeError
178 _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
179 {
180   int err = 0;
181
182   err = _gpgme_op_reset (ctx, synchronous);
183   if (err)
184     goto leave;
185
186   /* Check the supplied data */
187   if (!keydata)
188     {
189       err = GPGME_No_Data;
190       goto leave;
191     }
192
193   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
194   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
195
196   err = _gpgme_engine_op_import (ctx->engine, keydata);
197
198  leave:
199   if (err)
200     {
201       ctx->pending = 0;
202       _gpgme_engine_release (ctx->engine);
203       ctx->engine = NULL;
204     }
205   return err;
206 }
207
208
209 GpgmeError
210 gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
211 {
212   return _gpgme_op_import_start (ctx, 0, keydata);
213 }
214
215 /**
216  * gpgme_op_import:
217  * @c: Context 
218  * @keydata: Data object
219  * @nr: Will contain number of considered keys.
220  * 
221  * Import all key material from @keydata into the key database.
222  * 
223  * Return value: 0 on success or an error code.
224  **/
225 GpgmeError
226 gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr)
227 {
228   GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);
229   if (!err)
230     err = _gpgme_wait_one (ctx);
231   if (!err && nr)
232     {
233       if (ctx->result.import)
234         *nr = ctx->result.import->nr_considered;
235       else
236         *nr = 0;
237     }
238   return err;
239 }
240
241 GpgmeError
242 gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)
243 {
244   return gpgme_op_import_ext (ctx, keydata, 0);
245 }
246