/[winpt]/trunk/Src/wptImportList.cpp
ViewVC logotype

Contents of /trunk/Src/wptImportList.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 187 - (show annotations)
Wed Mar 22 11:04:20 2006 UTC (18 years, 11 months ago) by twoaday
File size: 10952 byte(s)
2006-03-21  Timo Schulz  <ts@g10code.de>
 
        * wptUTF8.cpp (native_to_utf8): Use directly W32 API.
        (utf8_to_native): Likewise. Remove cp850 conversion.
        * wptKeyEditDlgs.cpp (do_find_userid): Correct UTF8 handling.
        * wptKeyManager.cpp (km_delete_keys): Do not reset 'with_seckey'
        flag.

Prepare new release...


1 /* wptImportList.cpp
2 * Copyright (C) 2001-2005 Timo Schulz
3 * Copyright (C) 2005 g10 Code GmbH
4 *
5 * This file is part of WinPT.
6 *
7 * WinPT is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * WinPT 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 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 WinPT; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <windows.h>
27 #include <sys/types.h>
28 #include <ctype.h>
29
30 #include "wptTypes.h"
31 #include "wptGPG.h"
32 #include "wptCommonCtl.h"
33 #include "wptKeylist.h"
34 #include "wptNLS.h"
35 #include "wptErrors.h"
36 #include "wptUTF8.h"
37 #include "wptW32API.h"
38 #include "wptRegistry.h"
39 #include "openpgp.h"
40
41
42 /* Symbolic column ids */
43 enum impl_col_t {
44 IMPL_COL_UID = 0,
45 IMPL_COL_SIZE = 1,
46 IMPL_COL_KEYID = 2,
47 IMPL_COL_CREATION = 3,
48 IMPL_COL_KTYPE = 4
49 };
50
51 /* context to hold information about a key. */
52 struct import_key_s {
53 /* primary userid */
54 char *uid;
55
56 /* 1 = secret key is available. */
57 int secret;
58
59 /* flags */
60 unsigned int disabled:1;
61 unsigned int expired:1;
62 unsigned int revoked:1;
63
64 /* primary key attributes */
65 char keyid[16+1];
66 gpgme_pubkey_algo_t pubkey_algo;
67 size_t length;
68 time_t timestamp;
69
70 /* secondary key attributes */
71 char subkey_keyid[16+1];
72 gpgme_pubkey_algo_t subkey_algo;
73 size_t subkey_length;
74 time_t subkey_timestamp;
75 };
76 typedef struct import_key_s *import_key_t;
77
78
79 /* Release the key in @c. */
80 static void
81 import_key_release (import_key_t c)
82 {
83 if (!c)
84 return;
85 if (c->uid)
86 free (c->uid);
87 free (c);
88 }
89
90
91 /* Decode the %-encoded userid in @pend and store it as the first
92 userid in the key @c. */
93 static void
94 decode_userid (char *pend, import_key_t c)
95 {
96 c->uid = (char*)calloc (1, strlen (pend) + 1);
97 if (!c->uid)
98 BUG (NULL);
99 gpg_decode_c_string (pend, &c->uid, strlen (pend) + 1);
100 c->uid[strlen (c->uid) -3] = '\0';
101 }
102
103
104 /* Parse the output of 'gpg --with-colons <data'. */
105 static void
106 parse_colon_key (char *buf, import_key_t c)
107 {
108 const char * s;
109 char *p, *pend;
110 int field = 0, rectype = 0;
111 enum key_t {
112 KEY_none = 0,
113 KEY_primary = 1,
114 KEY_secondary = 2,
115 };
116
117 if (!buf)
118 return; /* EOF */
119
120 if( !strncmp (buf, "pub", 3) || !strncmp (buf, "sec", 3)) {
121 rectype = KEY_primary;
122 if (*buf == 's')
123 c->secret = 1;
124 }
125 else if (!strncmp (buf, "sub", 3) || !strncmp (buf, "ssb", 3))
126 rectype = KEY_secondary;
127 else if (!strncmp (buf, "uid", 3)) {
128 if (!c->uid) {
129 const char *uid = buf+3;
130 while (uid && *uid == ':')
131 uid++;
132 decode_userid ((char *)uid, c);
133 }
134 return;
135 }
136 else
137 return;
138
139 for (p = buf; p; p = pend) {
140 field++;
141 pend = strchr (p, ':');
142 if (pend)
143 *pend++ = 0;
144
145 switch (field) {
146 case 1:
147 if (rectype != KEY_primary)
148 break;
149 for (s = pend; *s && !isdigit ((unsigned int)*s); s++) {
150 switch (*s) {
151 case 'd': c->disabled = 1;break;
152 case 'e': c->expired = 1; break;
153 case 'r': c->revoked = 1; break;
154 }
155 }
156 break;
157
158 case 2:
159 if (rectype == KEY_primary)
160 c->length = atoi (pend);
161 else if (rectype == KEY_secondary)
162 c->subkey_length = atoi (pend);
163 break;
164
165 case 3:
166 if (rectype == KEY_primary)
167 c->pubkey_algo = (gpgme_pubkey_algo_t)atoi (pend);
168 else if (rectype == KEY_secondary)
169 c->subkey_algo = (gpgme_pubkey_algo_t)atoi (pend);
170 break;
171
172 case 4:
173 if (rectype == KEY_primary) {
174 strncpy (c->keyid, pend, 16);
175 c->keyid[16] = 0;
176 }
177 else if (rectype == KEY_secondary) {
178 strncpy (c->subkey_keyid, pend, 16);
179 c->subkey_keyid[16] = 0;
180 }
181 break;
182
183 case 5:
184 if (rectype == KEY_primary)
185 c->timestamp = strtoul (pend, NULL, 10);
186 else if (rectype == KEY_secondary)
187 c->subkey_timestamp = strtoul (pend, NULL, 10);
188 break;
189
190 case 9:
191 if (rectype == KEY_primary && !c->uid && strlen (pend) > 2) {
192 if (!strchr (pend, '[') && !strchr (pend, ']'))
193 decode_userid (pend, c);
194 }
195 break;
196 }
197 }
198 }
199
200 /* Read the next key from data stream @out. The result is stored in @r_key.
201 Return value: 0 on success. */
202 gpgme_error_t
203 gpg_import_next_key (gpgme_data_t out, char **pending_line, import_key_t *r_key)
204 {
205 import_key_t key;
206 int in_cert, got_block = 0;
207 char buf[384];
208 int n=0;
209
210 if (!r_key)
211 return gpg_error (GPG_ERR_INV_ARG);
212
213 key = (import_key_t) calloc (1, sizeof *key);
214 if (!key)
215 return gpg_error (GPG_ERR_ENOMEM);
216
217 if (*pending_line) {
218 parse_colon_key (*pending_line, key);
219 safe_free (*pending_line);
220 *pending_line = NULL;
221 in_cert = 1;
222 }
223 else
224 in_cert = 0;
225
226 while ((n=gpg_data_readline (out, buf, sizeof buf-1)) > 0) {
227 if (!strncmp (buf, "pub", 3) || !strncmp (buf, "sec", 3)) {
228 if (in_cert) {
229 *pending_line = strdup (buf);
230 goto ready;
231 }
232 in_cert = 1;
233 got_block = 1;
234 parse_colon_key (buf, key);
235 }
236 else if (in_cert) {
237 parse_colon_key (buf, key);
238 got_block = 1;
239 }
240 }
241 ready:
242 *r_key = key;
243 if (got_block && n == 0)
244 return 0;
245 return n == 0? gpg_error (GPG_ERR_EOF) : 0;
246 }
247
248
249 /* Return a humand readable key description of @key. */
250 static char*
251 key_description (import_key_t key)
252 {
253 gpgme_pubkey_algo_t pkalgo;
254 gpgme_pubkey_algo_t subalgo = (gpgme_pubkey_algo_t)0;
255 const char *type, *state;
256 char *p;
257 int n=0;
258
259 pkalgo = key->pubkey_algo;
260 if (key->subkey_algo)
261 subalgo = key->subkey_algo;
262 if (key->revoked)
263 state = _("Revoked" );
264 else if (key->expired)
265 state = _("Expired" );
266 else
267 state = "";
268 if (key->secret)
269 type = _("secret key");
270 else
271 type = _("public key");
272
273 n = strlen (state) + strlen (type) + 2*8 + 8;
274 p = new char[n+1];
275 if (!p)
276 BUG (NULL);
277
278 if (!subalgo)
279 _snprintf (p, 64, "%s %s %s", state,
280 get_key_pubalgo (pkalgo),type);
281 else
282 _snprintf (p, 64, "%s %s/%s %s", state,
283 get_key_pubalgo (pkalgo),
284 get_key_pubalgo (subalgo), type);
285 return p;
286 }
287
288
289 /* Add the key @key to the list view control @lv at position @pos. */
290 static int
291 implist_add_key (listview_ctrl_t lv, int pos, import_key_t key)
292 {
293 char *uid = NULL;
294 char buf[128], * desc;
295 const char *t;
296 u32 tt, tt2=0;
297
298 if (listview_add_item( lv, " " ))
299 return WPTERR_GENERAL;
300 t = key->uid;
301 if (!t || strlen (t) < 5) {
302 t = _("Invalid user ID");
303 listview_add_sub_item (lv, pos, IMPL_COL_UID, t);
304 }
305 else {
306 uid = utf8_to_native (t);
307 if (uid) {
308 listview_add_sub_item (lv, pos, IMPL_COL_UID, uid);
309 free (uid);
310 }
311 }
312
313 tt = key->length;
314 if (key->subkey_length > 0)
315 tt2 = key->subkey_length;
316 if (tt && tt2)
317 _snprintf (buf, sizeof buf - 1, "%d/%d", tt, tt2);
318 else
319 _snprintf (buf, sizeof buf-1, "%d", tt);
320 listview_add_sub_item (lv, pos, IMPL_COL_SIZE, buf);
321
322 t = key->keyid;
323 if (!t || strlen (t) < 8)
324 t = "????????????????";
325 _snprintf (buf, sizeof buf -1, "0x%s", t+8);
326 listview_add_sub_item (lv, pos, IMPL_COL_KEYID, buf);
327
328
329 tt = key->timestamp;
330 t = get_key_created (tt);
331 if( !t )
332 t = "????" "-??" "-??";
333 listview_add_sub_item (lv, pos, IMPL_COL_CREATION, (char *)t);
334
335 desc = key_description (key);
336 if (desc) {
337 listview_add_sub_item (lv, pos, IMPL_COL_KTYPE, desc);
338 free_if_alloc (desc);
339 }
340
341 return 0;
342 }
343
344
345 /* Create a list view for list keys. */
346 int
347 implist_build (listview_ctrl_t *lv, HWND ctrl)
348 {
349 struct listview_ctrl_s *c;
350 struct listview_column_s implist[] = {
351 {0, 190, (char *)_("User ID")},
352 {1, 66, (char *)_("Size")},
353 {2, 80, (char *)_("Key ID")},
354 {3, 72, (char *)_("Creation")},
355 {4, 132, (char *)_("Type")},
356 {0, 0, NULL}
357 };
358 int j, rc = 0;
359
360 rc = listview_new (&c);
361 if( rc )
362 return rc;
363 c->ctrl = ctrl;
364 for (j = 0; implist[j].fieldname != NULL; j++)
365 listview_add_column (c, &implist[j]);
366 listview_set_ext_style (c);
367 *lv = c;
368 return 0;
369 }
370
371
372 static int
373 check_import_data (const char *fname, int *r_revcert)
374 {
375 FILE *f;
376 char buf[512];
377 int n;
378
379 f = fopen (fname, "rb");
380 if (!f)
381 return -1;
382
383 *r_revcert = 0;
384 n = fread (buf, 1, 511, f);
385 if (n > 0) {
386 buf[n] = 0;
387 if (strstr (buf, "A revocation certificate should follow"))
388 *r_revcert = 1;
389 }
390
391 fclose (f);
392 return 0;
393 }
394
395
396 /* Load the list view @lv with the contents of the file @file.
397 @r_revcerts contains the number of revocation certs and
398 @r_seckeys the number of imported secret keys. */
399 int
400 implist_load (listview_ctrl_t lv, const char *file,
401 int *r_revcerts, int *r_seckeys)
402 {
403 gpgme_data_t list;
404 gpgme_error_t err;
405 import_key_t key;
406 int rc = 0, is_tmp=0;
407 char *pending_line = NULL;
408 char fname[300], *out;
409
410 if (!file) {
411 err = gpg_data_new_from_clipboard (&list, 0);
412 if (err) {
413 msg_box (NULL, gpgme_strerror( err ), _("Import"), MB_ERR);
414 return WPTERR_CLIP_OPEN;
415 }
416 get_temp_name (fname, 299, "in_gpg_keys");
417 err = gpg_data_release_and_set_file (list, fname);
418 if (err) {
419 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
420 return WPTERR_FILE_CREAT;
421 }
422 file = fname;
423 is_tmp = 1;
424 }
425
426 if (check_import_data (file, r_revcerts)) {
427 msg_box (NULL, _("It is possible that the ASCII-Armor is damaged\n"
428 "and thus a CRC error occurs."),
429 _("Import"), MB_ERR);
430 if (is_tmp)
431 DeleteFile (file);
432 return WPTERR_GENERAL;
433 }
434
435 err = gpg_import_key_list (file, &out);
436 if (err) {
437 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
438 if (is_tmp)
439 DeleteFile (file);
440 return WPTERR_GENERAL;
441 }
442
443 err = gpgme_data_new_from_mem (&list, out, strlen (out), 1);
444 free (out);
445 if (err) {
446 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
447 if (is_tmp)
448 DeleteFile (file);
449 return WPTERR_GENERAL;
450 }
451
452 if (r_seckeys)
453 *r_seckeys = 0;
454 while (!rc) {
455 /* XXX if the key has a direct key signature, the user-id field
456 in the --with-colons mode is empty! */
457 rc = gpg_import_next_key (list, &pending_line, &key);
458 if (!rc)
459 rc = implist_add_key (lv, 0, key);
460 if (key->secret)
461 (*r_seckeys)++;
462 import_key_release (key);
463 }
464
465 gpgme_data_release (list);
466 if (is_tmp)
467 DeleteFile (file);
468 return rc;
469 }
470
471
472 /* Release the list view @lv. */
473 void
474 implist_delete (listview_ctrl_t lv)
475 {
476 if (lv) {
477 listview_release (lv);
478 }
479 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26