* gpgsm/t-import.c (print_op_info): New.
[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 any_imported;
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   xfree (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, GpgStatusCode 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 != STATUS_EOF)
72     {
73       if (!args)
74         return;
75
76       if (code == STATUS_IMPORTED)
77         field_name = imported_fields;
78       else if (code == 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 == 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 == STATUS_EOF)
113     {
114       /* Just close the XML containter.  */
115       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
116     }
117   else
118     {
119       if (code == STATUS_IMPORTED)
120         _gpgme_data_append_string (dh, "  <import>\n");
121       else if (code == 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 (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 == STATUS_IMPORTED)
136         _gpgme_data_append_string (dh, "  </import>\n");
137       else if (code == STATUS_IMPORT_RES)
138         _gpgme_data_append_string (dh, "  </importResult>\n");
139     }
140 }
141
142
143 static void
144 import_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
145 {
146   if (ctx->error)
147     return;
148   test_and_allocate_result (ctx, import);
149
150   switch (code)
151     {
152     case STATUS_EOF:
153       if (ctx->result.import->xmlinfo)
154         {
155           append_xml_impinfo (&ctx->result.import->xmlinfo, code, NULL);
156           _gpgme_set_op_info (ctx, ctx->result.import->xmlinfo);
157           ctx->result.import->xmlinfo = NULL;
158         }
159       /* XXX Calculate error value.  */
160       break;
161
162     case STATUS_IMPORTED:
163       ctx->result.import->any_imported = 1;
164     case STATUS_IMPORT_RES:
165       append_xml_impinfo (&ctx->result.import->xmlinfo, code, args);
166       break;
167
168     default:
169       break;
170     }
171 }
172
173
174 static GpgmeError
175 _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
176 {
177   int err = 0;
178
179   err = _gpgme_op_reset (ctx, synchronous);
180   if (err)
181     goto leave;
182
183   /* Check the supplied data */
184   if (gpgme_data_get_type (keydata) == GPGME_DATA_TYPE_NONE)
185     {
186       err = mk_error (No_Data);
187       goto leave;
188     }
189   _gpgme_data_set_mode (keydata, GPGME_DATA_MODE_OUT);
190
191   _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
192   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
193
194   _gpgme_engine_op_import (ctx->engine, keydata);
195
196   if (!err)
197     err = _gpgme_engine_start (ctx->engine, ctx);
198
199  leave:
200   if (err)
201     {
202       ctx->pending = 0;
203       _gpgme_engine_release (ctx->engine);
204       ctx->engine = NULL;
205     }
206   return err;
207 }
208
209
210 GpgmeError
211 gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
212 {
213   return _gpgme_op_import_start (ctx, 0, keydata);
214 }
215
216 /**
217  * gpgme_op_import:
218  * @c: Context 
219  * @keydata: Data object
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 (GpgmeCtx ctx, GpgmeData keydata)
227 {
228   GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);
229   if (!err)
230     err = _gpgme_wait_one (ctx);
231   if (!err && (!ctx->result.import || !ctx->result.import->any_imported))
232     err = -1; /* Nothing at all imported. */
233   return err;
234 }
235