1 |
/* keylist.c - key listing |
2 |
* Copyright (C) 2000, 2001 Werner Koch (dd9jn), g10 Code GmbH |
3 |
* Copyright (C) 2002-2005 Timo Schulz |
4 |
* |
5 |
* This file is part of MyGPGME. |
6 |
* |
7 |
* MyGPGME 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 |
* MyGPGME 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 <stdio.h> |
23 |
#include <stdlib.h> |
24 |
#include <string.h> |
25 |
#include <time.h> |
26 |
#include <ctype.h> |
27 |
#include <assert.h> |
28 |
#include <windows.h> |
29 |
|
30 |
#include "util.h" |
31 |
#include "context.h" |
32 |
#include "ops.h" |
33 |
#include "key.h" |
34 |
|
35 |
static void finish_key ( gpgme_ctx_t ctx ); |
36 |
|
37 |
|
38 |
static void |
39 |
keylist_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char *args ) |
40 |
{ |
41 |
if( ctx->out_of_core ) |
42 |
return; |
43 |
|
44 |
switch( code ) { |
45 |
case STATUS_EOF: |
46 |
if( ctx->tmp_key ) |
47 |
finish_key( ctx ); |
48 |
break; |
49 |
|
50 |
default: /* ignore all other codes */ |
51 |
break; |
52 |
} |
53 |
} |
54 |
|
55 |
|
56 |
|
57 |
static time_t |
58 |
parse_timestamp( char * p ) |
59 |
{ |
60 |
return *p ? (time_t)strtoul( p, NULL, 10 ) : 0; |
61 |
} |
62 |
|
63 |
|
64 |
static void |
65 |
set_mainkey_trust_info( gpgme_key_t key, const char * s ) |
66 |
{ |
67 |
/* look at letters and stop at the first digit */ |
68 |
for( ; *s && !isdigit( *s ); s++ ) { |
69 |
switch( *s ) { |
70 |
case 'u': key->gloflags.ultimate = 1; |
71 |
key->validity = GPGME_VALIDITY_ULTIMATE; break; |
72 |
case '-': |
73 |
case 'q': key->validity = GPGME_VALIDITY_UNDEFINED; break; |
74 |
case 'm': key->validity = GPGME_VALIDITY_MARGINAL; break; |
75 |
case 'f': key->validity = GPGME_VALIDITY_FULL; break; |
76 |
case 'e': key->keys.flags.expired = 1; break; |
77 |
case 'r': key->keys.flags.revoked = 1; |
78 |
key->validity = GPGME_VALIDITY_REVOKED; break; |
79 |
case 'd': key->keys.flags.disabled = 1; break; |
80 |
case 'i': key->keys.flags.invalid = 1; break; |
81 |
} |
82 |
} |
83 |
} |
84 |
|
85 |
|
86 |
static void |
87 |
set_userid_flags (struct user_id_s * u, const char * s) |
88 |
{ |
89 |
/* look at letters and stop at the first digit */ |
90 |
for (; *s && !isdigit (*s); s++) { |
91 |
switch( *s ) { |
92 |
case 'r': u->flags.revoked = 1; |
93 |
u->validity = GPGME_VALIDITY_REVOKED; break; |
94 |
case 'i': u->flags.invalid = 1; |
95 |
u->validity = GPGME_VALIDITY_UNDEFINED; break; |
96 |
case 'n': u->validity = GPGME_VALIDITY_NEVER; break; |
97 |
case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break; |
98 |
case 'f': u->validity = GPGME_VALIDITY_FULL; break; |
99 |
case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break; |
100 |
} |
101 |
} |
102 |
} |
103 |
|
104 |
static void |
105 |
set_subkey_trust_info( struct subkey_s * k, const char * s ) |
106 |
{ |
107 |
/* look at letters and stop at the first digit */ |
108 |
for( ; *s && !isdigit (*s); s++ ) { |
109 |
switch( *s ) { |
110 |
case 'e': k->flags.expired = 1; break; |
111 |
case 'r': k->flags.revoked = 1; break; |
112 |
case 'd': k->flags.disabled = 1; break; |
113 |
case 'i': k->flags.invalid = 1; break; |
114 |
} |
115 |
} |
116 |
} |
117 |
|
118 |
static void |
119 |
set_mainkey_capability( gpgme_key_t key, const char * s ) |
120 |
{ |
121 |
for( ; *s ; s++ ) { |
122 |
switch( *s ) { |
123 |
case 'a': key->keys.flags.can_auth = 1; break; |
124 |
case 'e': key->keys.flags.can_encrypt = 1; break; |
125 |
case 's': key->keys.flags.can_sign = 1; break; |
126 |
case 'c': key->keys.flags.can_certify = 1; break; |
127 |
case 'E': key->gloflags.can_encrypt = 1; break; |
128 |
case 'S': key->gloflags.can_sign = 1; break; |
129 |
case 'C': key->gloflags.can_certify = 1; break; |
130 |
case 'D': key->gloflags.disabled = 1; break; |
131 |
} |
132 |
} |
133 |
} |
134 |
|
135 |
static void |
136 |
set_subkey_capability (struct subkey_s * k, const char * s) |
137 |
{ |
138 |
for (; *s; s++) { |
139 |
switch (*s) { |
140 |
case 'a': k->flags.can_auth = 1; break; |
141 |
case 'e': k->flags.can_encrypt = 1; break; |
142 |
case 's': k->flags.can_sign = 1; break; |
143 |
case 'c': k->flags.can_certify = 1; break; |
144 |
} |
145 |
} |
146 |
} |
147 |
|
148 |
static void |
149 |
set_mainkey_ownertrust( gpgme_key_t key, const char * s ) |
150 |
{ |
151 |
switch( *s ) { |
152 |
case '-': key->otrust = GPGME_TRUST_UNKNOWN; break; |
153 |
case 'e': key->otrust = GPGME_TRUST_EXPIRED; break; |
154 |
case 'q': key->otrust = GPGME_TRUST_UNDEFINED; break; |
155 |
case 'n': key->otrust = GPGME_TRUST_NEVER; break; |
156 |
case 'm': key->otrust = GPGME_TRUST_MARGINAL; break; |
157 |
case 'f': key->otrust = GPGME_TRUST_FULLY; break; |
158 |
case 'u': key->otrust = GPGME_TRUST_ULTIMATE; break; |
159 |
default: key->otrust = GPGME_TRUST_UNKNOWN; break; |
160 |
} |
161 |
} |
162 |
|
163 |
|
164 |
/* Note: we are allowed to modify line */ |
165 |
static void |
166 |
keylist_colon_handler( gpgme_ctx_t ctx, char * line ) |
167 |
{ |
168 |
enum { |
169 |
RT_NONE, |
170 |
RT_SIG, |
171 |
RT_UID, |
172 |
RT_SUB, |
173 |
RT_PUB, |
174 |
RT_FPR, |
175 |
RT_SSB, |
176 |
RT_SEC, |
177 |
RT_PKD, |
178 |
} rectype = RT_NONE; |
179 |
gpgme_key_t key = ctx->tmp_key; |
180 |
struct subkey_s * sk = NULL; |
181 |
struct signature_s * sig = NULL; |
182 |
struct subkey_s * s = NULL; |
183 |
struct user_id_s * u = NULL; |
184 |
struct mpi_s * m = NULL, * mt = NULL; |
185 |
const char * trust_info = NULL; |
186 |
char * p, * pend; |
187 |
int field = 0; |
188 |
unsigned long val=0; |
189 |
int i; |
190 |
|
191 |
if( ctx->out_of_core ) |
192 |
return; |
193 |
if( !line ) { /* EOF */ |
194 |
if( ctx->tmp_key ) |
195 |
finish_key( ctx ); |
196 |
return; |
197 |
} |
198 |
|
199 |
for( p = line; p; p = pend ) { |
200 |
field++; |
201 |
pend = strchr( p, ':' ); |
202 |
if( pend ) |
203 |
*pend++ = 0; |
204 |
|
205 |
if( field == 1 ) { |
206 |
if( !strcmp( p, "sig" ) && key ) { |
207 |
rectype = RT_SIG; |
208 |
sig = _gpgme_key_add_signature( key ); |
209 |
if( !sig ) { |
210 |
ctx->out_of_core = 1; |
211 |
break; |
212 |
} |
213 |
} |
214 |
else if( !strcmp( p, "uid" ) && key ) { |
215 |
rectype = RT_UID; |
216 |
key = ctx->tmp_key; |
217 |
sig = _gpgme_key_add_signature( key ); |
218 |
if( !sig ) { |
219 |
ctx->out_of_core = 1; |
220 |
break; |
221 |
} |
222 |
} |
223 |
else if( !strcmp( p, "sub" ) && key ) { |
224 |
/* start a new subkey */ |
225 |
rectype = RT_SUB; |
226 |
sk = _gpgme_key_add_subkey( key ); |
227 |
if( !sk ) { |
228 |
ctx->out_of_core = 1; |
229 |
return; |
230 |
} |
231 |
} |
232 |
else if( !strcmp( p, "ssb" ) && key ) { |
233 |
/* start a new secret subkey */ |
234 |
rectype = RT_SSB; |
235 |
sk = _gpgme_key_add_secret_subkey( key ); |
236 |
if( !sk ) { |
237 |
ctx->out_of_core = 1; |
238 |
return; |
239 |
} |
240 |
} |
241 |
else if( !strcmp( p, "pub" ) ) { |
242 |
/* start a new keyblock */ |
243 |
if( _gpgme_key_new ( &key ) ) { |
244 |
ctx->out_of_core = 1; /* the only kind of error we can get*/ |
245 |
return; |
246 |
} |
247 |
rectype = RT_PUB; |
248 |
if ( ctx->tmp_key ) |
249 |
finish_key ( ctx ); |
250 |
assert ( !ctx->tmp_key ); |
251 |
ctx->tmp_key = key; |
252 |
ctx->tmp_i = 0; |
253 |
if (ctx->cb.progress) |
254 |
ctx->cb.progress (ctx->cb.progress_value, "keylist", 0, |
255 |
ctx->cb.progess_tmp, |
256 |
ctx->cb.progress_value_int); |
257 |
ctx->cb.progess_tmp++; |
258 |
} |
259 |
else if( !strcmp ( p, "sec" ) ) { |
260 |
/* start a new keyblock */ |
261 |
if ( _gpgme_key_new_secret( &key ) ) { |
262 |
ctx->out_of_core = 1; /* the only kind of error we can get */ |
263 |
return; |
264 |
} |
265 |
rectype = RT_SEC; |
266 |
if( ctx->tmp_key ) |
267 |
finish_key ( ctx ); |
268 |
assert ( !ctx->tmp_key ); |
269 |
ctx->tmp_key = key; |
270 |
} |
271 |
else if( !strcmp( p, "fpr" ) && key ) |
272 |
rectype = RT_FPR; |
273 |
else if( !strcmp( p, "pkd" ) && key ) |
274 |
rectype = RT_PKD; |
275 |
else |
276 |
rectype = RT_NONE; |
277 |
} |
278 |
else if( rectype == RT_PUB || rectype == RT_SEC ) |
279 |
{ |
280 |
switch( field ) { |
281 |
case 2: /* trust info */ |
282 |
trust_info = p; |
283 |
set_mainkey_trust_info( key, trust_info ); |
284 |
break; |
285 |
case 3: /* key length */ |
286 |
i = atoi( p ); |
287 |
if( i > 1 ) /* ignore invalid values */ |
288 |
key->keys.key_len = i; |
289 |
break; |
290 |
case 4: /* pubkey algo */ |
291 |
i = atoi ( p ); |
292 |
if( i > 0 && i < 128 ) |
293 |
key->keys.key_algo = i; |
294 |
break; |
295 |
case 5: /* long keyid */ |
296 |
memset (key->keys.keyid, 0, sizeof key->keys.keyid); |
297 |
strncpy (key->keys.keyid, p, DIM (key->keys.keyid)-1); |
298 |
break; |
299 |
case 6: /* timestamp (1998-02-28) */ |
300 |
key->keys.timestamp = parse_timestamp( p ); |
301 |
break; |
302 |
case 7: /* valid for n days */ |
303 |
key->keys.expires = parse_timestamp( p ); |
304 |
break; |
305 |
case 8: /* reserved (LID) */ |
306 |
break; |
307 |
case 9: /* ownertrust */ |
308 |
set_mainkey_ownertrust( key, p ); |
309 |
break; |
310 |
case 10: /* not used due to --fixed-list-mode option */ |
311 |
break; |
312 |
case 11: /* signature class */ |
313 |
break; |
314 |
case 12: /* capabilities */ |
315 |
set_mainkey_capability( key, p ); |
316 |
break; |
317 |
case 15: |
318 |
if (p && * p) |
319 |
{ |
320 |
key->gloflags.divert_to_card = 1; |
321 |
memset (key->keys.cardno, 0, sizeof key->keys.cardno); |
322 |
strncpy (key->keys.cardno, p, DIM (key->keys.cardno)); |
323 |
} |
324 |
pend = NULL; /* we can stop here */ |
325 |
break; |
326 |
} |
327 |
} |
328 |
else if( (rectype == RT_SUB || rectype== RT_SSB) && sk ) { |
329 |
switch( field ) { |
330 |
case 2: /* trust info */ |
331 |
set_subkey_trust_info( sk, p ); |
332 |
break; |
333 |
case 3: /* key length */ |
334 |
i = atoi( p ); |
335 |
if ( i > 1 ) /* ignore invalid values */ |
336 |
sk->key_len = i; |
337 |
break; |
338 |
case 4: /* pubkey algo */ |
339 |
i = atoi( p ); |
340 |
if( i > 0 && i < 128 ) |
341 |
sk->key_algo = i; |
342 |
break; |
343 |
case 5: /* long keyid */ |
344 |
memset (sk->keyid, 0, sizeof sk->keyid); |
345 |
strncpy (sk->keyid, p, DIM (sk->keyid)-1); |
346 |
break; |
347 |
case 6: /* timestamp (1998-02-28) */ |
348 |
sk->timestamp = parse_timestamp( p ); |
349 |
break; |
350 |
case 7: /* valid for n days */ |
351 |
sk->expires = parse_timestamp( p ); |
352 |
break; |
353 |
case 8: /* reserved (LID) */ |
354 |
break; |
355 |
case 9: /* ownertrust */ |
356 |
break; |
357 |
case 10:/* user ID n/a for a subkey */ |
358 |
break; |
359 |
case 11: /* signature class */ |
360 |
break; |
361 |
case 12: /* capability */ |
362 |
set_subkey_capability ( sk, p ); |
363 |
break; |
364 |
case 15: |
365 |
memset (sk->cardno, 0, sizeof sk->cardno); |
366 |
strncpy (sk->cardno, p, DIM (sk->cardno)-1); |
367 |
pend = NULL; /* we can stop here */ |
368 |
break; |
369 |
} |
370 |
} |
371 |
else if (rectype == RT_UID) |
372 |
{ |
373 |
switch (field) |
374 |
{ |
375 |
case 2: /* trust info */ |
376 |
trust_info = p; /* save for later use */ |
377 |
break; |
378 |
case 6: /* creation date */ |
379 |
if (p) |
380 |
val = parse_timestamp (p); |
381 |
break; |
382 |
|
383 |
case 8: /* hash over name */ |
384 |
break; |
385 |
|
386 |
case 10: /* user ID */ |
387 |
safe_free (ctx->tmp_id); |
388 |
ctx->tmp_id = strdup (p); |
389 |
if (!ctx->tmp_id) { |
390 |
ctx->out_of_core = 1; |
391 |
break; |
392 |
} |
393 |
if (_gpgme_key_append_name (key, p, &u)) |
394 |
ctx->out_of_core = 1; |
395 |
else if (trust_info) |
396 |
set_userid_flags (u, trust_info); |
397 |
if (sig) { |
398 |
safe_free (sig->issuer); |
399 |
sig->issuer = calloc (1, strlen (p) + 1); |
400 |
if (!sig->issuer) { |
401 |
ctx->out_of_core = 1; |
402 |
break; |
403 |
} |
404 |
_gpgme_decode_c_string (p, &sig->issuer, strlen (p)+ 1); |
405 |
} |
406 |
u->created = val; |
407 |
pend = NULL; /* we can stop here */ |
408 |
break; |
409 |
} |
410 |
} |
411 |
else if( rectype == RT_FPR ) { |
412 |
int nfpr = ctx->tmp_i; |
413 |
switch( field ) { |
414 |
case 10: |
415 |
for( s = &key->keys; s && nfpr; s = s->next, nfpr-- ) |
416 |
; |
417 |
if( s ) { |
418 |
s->fingerprint = strdup( p ); |
419 |
if( !s->fingerprint ) { |
420 |
ctx->out_of_core = 1; |
421 |
break; |
422 |
} |
423 |
} |
424 |
pend = NULL; /* that is all we want */ |
425 |
ctx->tmp_i++; |
426 |
break; |
427 |
} |
428 |
} |
429 |
else if( rectype == RT_SIG ) { |
430 |
switch( field ) { |
431 |
case 2: /* signature state */ |
432 |
switch( *p ) { |
433 |
case '!': sig->stat = GPGME_SIG_STAT_GOOD; break; |
434 |
case '-': sig->stat = GPGME_SIG_STAT_BAD; break; |
435 |
case '?': sig->stat = GPGME_SIG_STAT_NOKEY; break; |
436 |
case '%': sig->stat = GPGME_SIG_STAT_ERROR; break; |
437 |
default : sig->stat = GPGME_SIG_STAT_NONE; break; |
438 |
} |
439 |
break; |
440 |
|
441 |
case 4: /* pk algorithm */ |
442 |
sig->algo = atol (p); |
443 |
break; |
444 |
|
445 |
case 5: /* long keyid */ |
446 |
memset (sig->keyid, 0, sizeof sig->keyid); |
447 |
strncpy (sig->keyid, p, DIM (sig->keyid)-1); |
448 |
break; |
449 |
|
450 |
case 6: /* created */ |
451 |
sig->created = parse_timestamp( p ); |
452 |
break; |
453 |
|
454 |
case 7: /* expires */ |
455 |
sig->expires = parse_timestamp( p ); |
456 |
break; |
457 |
|
458 |
case 10: |
459 |
if( p ) { |
460 |
sig->issuer = calloc( 1, strlen( p ) + 1 ); |
461 |
if( !sig->issuer ) { |
462 |
ctx->out_of_core = 1; |
463 |
break; |
464 |
} |
465 |
_gpgme_decode_c_string( p, &sig->issuer, strlen( p ) + 1 ); |
466 |
} |
467 |
break; |
468 |
|
469 |
case 11: |
470 |
sig->sigclass = strtoul( p, NULL, 16 ); |
471 |
if (strchr (p, 'l')) |
472 |
sig->is_local = 1; |
473 |
/*if (strchr (p, ' ')) |
474 |
sig->is_nonrev = 1;*/ |
475 |
if (sig->sigclass < 0x10 || sig->sigclass > 0x13) { |
476 |
/* we only want certificates and no key signatures */ |
477 |
pend = NULL; |
478 |
break; |
479 |
} |
480 |
if( ctx->tmp_id ) { |
481 |
sig->user_id = calloc( 1, strlen( ctx->tmp_id ) + 1 ); |
482 |
if( !sig->user_id ) { |
483 |
ctx->out_of_core = 1; |
484 |
break; |
485 |
} |
486 |
_gpgme_decode_c_string( ctx->tmp_id, &sig->user_id, strlen( ctx->tmp_id ) +1 ); |
487 |
} |
488 |
pend = NULL; /* we can stop here */ |
489 |
break; |
490 |
} |
491 |
} |
492 |
else if( rectype == RT_PKD ) { |
493 |
switch( field ) { |
494 |
case 1: |
495 |
m = calloc( 1, sizeof * m ); |
496 |
if( !m ) { |
497 |
ctx->out_of_core = 1; |
498 |
return; |
499 |
} |
500 |
for( mt=key->pkey; mt->next; mt=mt->next ) |
501 |
; |
502 |
mt->next = m; |
503 |
break; |
504 |
|
505 |
case 2: |
506 |
if( m ) |
507 |
m->bits = atol( p ); |
508 |
break; |
509 |
|
510 |
case 3: |
511 |
if( m ) { |
512 |
m->hexval = strdup( p ); |
513 |
if( !m->hexval ) |
514 |
ctx->out_of_core=1; |
515 |
} |
516 |
break; |
517 |
} |
518 |
} |
519 |
} |
520 |
|
521 |
} |
522 |
|
523 |
|
524 |
/* |
525 |
* We have read an entire key into ctx->tmp_key and should now finish |
526 |
* it. It is assumed that this releases ctx->tmp_key. |
527 |
*/ |
528 |
static void |
529 |
finish_key( gpgme_ctx_t ctx ) |
530 |
{ |
531 |
gpgme_key_t key = ctx->tmp_key; |
532 |
struct key_queue_item_s * q, * q2; |
533 |
|
534 |
assert( key ); |
535 |
ctx->tmp_key = NULL; |
536 |
|
537 |
q = malloc( sizeof *q ); |
538 |
if( !q ) { |
539 |
gpgme_key_release( key ); |
540 |
ctx->out_of_core = 1; |
541 |
return; |
542 |
} |
543 |
q->key = key; |
544 |
q->next = NULL; |
545 |
/* fixme: lock queue. Use a tail pointer? */ |
546 |
q2 = ctx->key_queue; |
547 |
if( !q2 ) |
548 |
ctx->key_queue = q; |
549 |
else { |
550 |
for( ; q2->next; q2 = q2->next ) |
551 |
; |
552 |
q2->next = q; |
553 |
} |
554 |
ctx->key_cond = 1; |
555 |
/* fixme: unlock queue */ |
556 |
} |
557 |
|
558 |
|
559 |
|
560 |
/** |
561 |
* gpgme_op_keylist_start: |
562 |
* @c: context |
563 |
* @pattern: a GnuPg user ID or NULL for all |
564 |
* @secret_only: List only keys where the secret part is available |
565 |
* |
566 |
* Note that this function also cancels a pending key listing operaton.. |
567 |
* |
568 |
* Return value: 0 on success or an errorcode. |
569 |
**/ |
570 |
gpgme_error_t |
571 |
gpgme_op_keylist_start( gpgme_ctx_t ctx, const char *pattern, int secret_only ) |
572 |
{ |
573 |
gpgme_error_t rc = 0; |
574 |
|
575 |
if( !ctx ) |
576 |
return mk_error( Invalid_Value ); |
577 |
ctx->pending = 1; |
578 |
|
579 |
_gpgme_release_result( ctx ); |
580 |
ctx->out_of_core = 0; |
581 |
ctx->cb.progess_tmp = 0; |
582 |
|
583 |
_gpgme_gpg_release( &ctx->gpg ); |
584 |
gpgme_key_release( ctx->tmp_key ); |
585 |
ctx->tmp_key = NULL; |
586 |
/* Fixme: release key_queue */ |
587 |
|
588 |
rc = _gpgme_gpg_new( &ctx->gpg ); |
589 |
if( rc ) |
590 |
goto leave; |
591 |
|
592 |
_gpgme_gpg_set_status_handler( ctx->gpg, keylist_status_handler, ctx ); |
593 |
rc = _gpgme_gpg_set_colon_line_handler( ctx->gpg, keylist_colon_handler, ctx ); |
594 |
if ( rc ) |
595 |
goto leave; |
596 |
|
597 |
/* build the commandline */ |
598 |
if (ctx->use_logging) |
599 |
_gpgme_gpg_set_logging_handler (ctx->gpg, ctx); |
600 |
_gpgme_gpg_set_list_options (ctx->gpg, ctx->list_opts); |
601 |
_gpgme_gpg_add_arg( ctx->gpg, "--with-colons" ); |
602 |
_gpgme_gpg_add_arg( ctx->gpg, "--fixed-list-mode" ); |
603 |
_gpgme_gpg_add_arg( ctx->gpg, "--with-fingerprint" ); |
604 |
_gpgme_gpg_add_arg( ctx->gpg, "--with-fingerprint" ); /* for the subkey */ |
605 |
if( ctx->keylist_mode & 1 ) |
606 |
_gpgme_gpg_add_arg( ctx->gpg, "--no-expensive-trust-checks" ); |
607 |
if( ctx->keylist_mode & 2 ) |
608 |
_gpgme_gpg_add_arg( ctx->gpg, "--with-key-data" ); |
609 |
if( ctx->keylist_mode & 4 ) |
610 |
_gpgme_gpg_add_arg( ctx->gpg, "--fast-list-mode" ); |
611 |
if( 1 || !ctx->keylist_mode ) /* XXX: do all combinations make sense? */ |
612 |
_gpgme_gpg_add_arg( ctx->gpg, "-vvv" ); /* to list and check sigs */ |
613 |
_gpgme_gpg_add_arg ( ctx->gpg, secret_only? |
614 |
"--list-secret-keys": /*"--list-keys"*/ "-k" ); |
615 |
|
616 |
/* Tell the gpg object about the data */ |
617 |
_gpgme_gpg_add_arg ( ctx->gpg, "--" ); |
618 |
if( pattern && *pattern ) |
619 |
_gpgme_gpg_add_arg ( ctx->gpg, pattern ); |
620 |
|
621 |
/* and kick off the process */ |
622 |
rc = _gpgme_gpg_spawn ( ctx->gpg, ctx ); |
623 |
|
624 |
leave: |
625 |
if( rc ) { |
626 |
ctx->pending = 0; |
627 |
_gpgme_gpg_release ( &ctx->gpg ); |
628 |
} |
629 |
return rc; |
630 |
} |
631 |
|
632 |
|
633 |
gpgme_error_t |
634 |
gpgme_op_keylist_next( gpgme_ctx_t ctx, gpgme_key_t * r_key ) |
635 |
{ |
636 |
struct key_queue_item_s * q; |
637 |
|
638 |
if( !r_key ) |
639 |
return mk_error( Invalid_Value ); |
640 |
*r_key = NULL; |
641 |
if( !ctx ) |
642 |
return mk_error( Invalid_Value ); |
643 |
if( !ctx->pending ) |
644 |
return mk_error( No_Request ); |
645 |
if( ctx->out_of_core ) |
646 |
return mk_error( Out_Of_Core ); |
647 |
|
648 |
if( !ctx->key_queue ) { |
649 |
_gpgme_wait_on_condition( ctx, 1, &ctx->key_cond ); |
650 |
if ( ctx->out_of_core ) |
651 |
return mk_error( Out_Of_Core ); |
652 |
if( !ctx->key_cond ) |
653 |
return mk_error( EOF ); |
654 |
ctx->key_cond = 0; |
655 |
assert ( ctx->key_queue ); |
656 |
} |
657 |
q = ctx->key_queue; |
658 |
ctx->key_queue = q->next; |
659 |
|
660 |
*r_key = q->key; |
661 |
safe_free (q); |
662 |
return 0; |
663 |
} |
664 |
|
665 |
|
666 |
gpgme_error_t |
667 |
gpgme_op_keylist_getkey (int is_sec, const char *pattern, gpgme_key_t *r_key) |
668 |
{ |
669 |
gpgme_ctx_t listctx; |
670 |
gpgme_error_t err; |
671 |
|
672 |
err = gpgme_new (&listctx); |
673 |
if (err) |
674 |
return err; |
675 |
err = gpgme_op_keylist_start (listctx, pattern, is_sec); |
676 |
if (!err) |
677 |
err = gpgme_op_keylist_next (listctx, r_key); |
678 |
gpgme_release (listctx); |
679 |
return err; |
680 |
} |