typo fix in comment.
[gpgme.git] / gpgme / keylist.c
1 /* keylist.c -  key listing
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 <time.h>
27 #include <assert.h>
28
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32 #include "key.h"
33
34 #define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
35
36 struct keylist_result_s
37 {
38   int truncated;
39   GpgmeData xmlinfo;
40 };
41
42 static void finish_key ( GpgmeCtx ctx );
43
44
45 void
46 _gpgme_release_keylist_result (KeylistResult result)
47 {
48   if (!result)
49     return;
50   xfree (result);
51 }
52
53 /* Append some XML info.  args is currently ignore but we might want
54    to add more information in the future (like source of the
55    keylisting.  With args of NULL the XML structure is closed.  */
56 static void
57 append_xml_keylistinfo (GpgmeData *rdh, char *args)
58 {
59   GpgmeData dh;
60
61   if (!*rdh)
62     {
63       if (gpgme_data_new (rdh))
64         return; /* FIXME: We are ignoring out-of-core.  */
65       dh = *rdh;
66       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
67     }
68   else
69     {
70       dh = *rdh;
71       _gpgme_data_append_string (dh, "  </keylisting>\n");
72     }
73
74   if (!args)
75     {
76       /* Just close the XML containter.  */
77       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
78       return;
79     }
80
81   _gpgme_data_append_string (dh,
82                              "  <keylisting>\n"
83                              "    <truncated/>\n"
84                              );
85     
86 }
87
88
89
90 static void
91 keylist_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
92 {
93   if (ctx->error)
94     return;
95   test_and_allocate_result (ctx, keylist);
96
97   switch (code)
98     {
99     case STATUS_TRUNCATED:
100       ctx->result.keylist->truncated = 1;
101       break;
102
103     case STATUS_EOF:
104       finish_key (ctx);
105       if (ctx->result.keylist->truncated)
106         append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, "1");
107       if (ctx->result.keylist->xmlinfo)
108         {
109           append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, NULL);
110           _gpgme_set_op_info (ctx, ctx->result.keylist->xmlinfo);
111           ctx->result.keylist->xmlinfo = NULL;
112         }
113       break;
114
115     default:
116       /* Ignore all other codes.  */
117       break;
118     }
119 }
120
121
122 static time_t
123 parse_timestamp (char *p)
124 {
125   if (!*p)
126     return 0;
127
128   return (time_t)strtoul (p, NULL, 10);
129 }
130
131
132 static void
133 set_mainkey_trust_info (GpgmeKey key, const char *s)
134 {
135   /* Look at letters and stop at the first digit.  */
136   for (; *s && !my_isdigit (*s); s++)
137     {
138       switch (*s)
139         {
140         case 'e': key->keys.flags.expired = 1; break;
141         case 'r': key->keys.flags.revoked = 1; break;
142         case 'd': key->keys.flags.disabled = 1; break;
143         case 'i': key->keys.flags.invalid = 1; break;
144         }
145     }
146 }
147
148
149 static void
150 set_userid_flags (GpgmeKey key, const char *s)
151 {
152   /* Look at letters and stop at the first digit.  */
153   for (; *s && !my_isdigit (*s); s++)
154     {
155       switch (*s)
156         {
157         case 'r': key->uids->revoked  = 1; break;
158         case 'i': key->uids->invalid  = 1; break;
159
160         case 'n': key->uids->validity = GPGME_VALIDITY_NEVER; break;
161         case 'm': key->uids->validity = GPGME_VALIDITY_MARGINAL; break;
162         case 'f': key->uids->validity = GPGME_VALIDITY_FULL; break;
163         case 'u': key->uids->validity = GPGME_VALIDITY_ULTIMATE; break;
164         }
165     }
166 }
167
168
169 static void
170 set_subkey_trust_info (struct subkey_s *k, const char *s)
171 {
172   /* Look at letters and stop at the first digit.  */
173   for (; *s && !my_isdigit (*s); s++)
174     {
175       switch (*s)
176         {
177         case 'e': k->flags.expired = 1; break;
178         case 'r': k->flags.revoked = 1; break;
179         case 'd': k->flags.disabled = 1; break;
180         case 'i': k->flags.invalid = 1; break;
181         }
182     }
183 }
184
185
186 static void
187 set_mainkey_capability (GpgmeKey key, const char *s)
188 {
189   for (; *s ; s++)
190     {
191       switch (*s)
192         {
193         case 'e': key->keys.flags.can_encrypt = 1; break;
194         case 's': key->keys.flags.can_sign = 1; break;
195         case 'c': key->keys.flags.can_certify = 1; break;
196         case 'E': key->gloflags.can_encrypt = 1; break;
197         case 'S': key->gloflags.can_sign = 1; break;
198         case 'C': key->gloflags.can_certify = 1; break;
199         }
200     }
201 }
202
203
204 static void
205 set_subkey_capability ( struct subkey_s *k, const char *s)
206 {
207   for (; *s; s++)
208     {
209       switch (*s)
210         {
211         case 'e': k->flags.can_encrypt = 1; break;
212         case 's': k->flags.can_sign = 1; break;
213         case 'c': k->flags.can_certify = 1; break;
214         }
215     }
216 }
217
218 static void
219 set_ownertrust (GpgmeKey key, const char *s)
220 {
221   /* Look at letters and stop at the first digit.  */
222   for (; *s && !my_isdigit (*s); s++)
223     {
224       switch (*s)
225         {
226         case 'n': key->otrust = GPGME_VALIDITY_NEVER; break;
227         case 'm': key->otrust = GPGME_VALIDITY_MARGINAL; break;
228         case 'f': key->otrust = GPGME_VALIDITY_FULL; break;
229         case 'u': key->otrust = GPGME_VALIDITY_ULTIMATE; break;
230         default : key->otrust = GPGME_VALIDITY_UNKNOWN; break;
231         }
232     }
233 }
234
235
236 /* Note: We are allowed to modify LINE.  */
237 static void
238 keylist_colon_handler (GpgmeCtx ctx, char *line)
239 {
240   char *p, *pend;
241   int field = 0;
242   enum
243     {
244       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
245       RT_CRT, RT_CRS
246     }
247   rectype = RT_NONE;
248   GpgmeKey key = ctx->tmp_key;
249   int i;
250   const char *trust_info = NULL;
251   struct subkey_s *sk = NULL;
252
253   if (ctx->error)
254     return;
255   if (!line)
256     {
257       /* EOF */
258       finish_key (ctx);
259       return; 
260     }
261   
262   for (p = line; p; p = pend)
263     {
264       field++;
265       pend = strchr (p, ':');
266       if (pend) 
267         *pend++ = 0;
268
269       if (field == 1)
270         {
271           if (!strcmp (p, "sig"))
272             rectype = RT_SIG;
273           else if (!strcmp (p, "uid") && key)
274             {
275               rectype = RT_UID;
276               key = ctx->tmp_key;
277             }
278           else if (!strcmp (p, "sub") && key)
279             {
280               /* Start a new subkey.  */
281               rectype = RT_SUB; 
282               if (!(sk = _gpgme_key_add_subkey (key)))
283                 {
284                   ctx->error = mk_error (Out_Of_Core);
285                   return;
286                 }
287             }
288           else if (!strcmp (p, "ssb") && key)
289             {
290               /* Start a new secret subkey.  */
291               rectype = RT_SSB;
292               if (!(sk = _gpgme_key_add_secret_subkey (key)))
293                 {
294                   ctx->error = mk_error (Out_Of_Core);
295                   return;
296                 }
297             }
298           else if (!strcmp (p, "pub"))
299             {
300               /* Start a new keyblock.  */
301               if (_gpgme_key_new (&key))
302                 {
303                   /* The only kind of error we can get.  */
304                   ctx->error = mk_error (Out_Of_Core);
305                   return;
306                 }
307               rectype = RT_PUB;
308               finish_key (ctx);
309               assert (!ctx->tmp_key);
310               ctx->tmp_key = key;
311             }
312           else if (!strcmp (p, "sec"))
313             {
314               /* Start a new keyblock,  */
315               if (_gpgme_key_new_secret (&key))
316                 {
317                   /* The only kind of error we can get.  */
318                   ctx->error = mk_error (Out_Of_Core);
319                   return;
320                 }
321               rectype = RT_SEC;
322               finish_key (ctx);
323               assert (!ctx->tmp_key);
324               ctx->tmp_key = key;
325             }
326           else if (!strcmp (p, "crt"))
327             {
328               /* Start a new certificate. */
329               if (_gpgme_key_new (&key))
330                 {
331                   /* The only kind of error we can get.  */
332                   ctx->error = mk_error (Out_Of_Core);
333                   return;
334                 }
335               key->x509 = 1;
336               rectype = RT_CRT;
337               finish_key (ctx);
338               assert (!ctx->tmp_key);
339               ctx->tmp_key = key;
340             }
341           else if (!strcmp (p, "crs"))
342             {
343               /* Start a new certificate.  */
344               if (_gpgme_key_new_secret (&key))
345                 {
346                   /* The only kind of error we can get.  */
347                   ctx->error = mk_error (Out_Of_Core);
348                   return;
349                 }
350               key->x509 = 1;
351               rectype = RT_CRS;
352               finish_key (ctx);
353               assert (!ctx->tmp_key);
354               ctx->tmp_key = key;
355             }
356           else if (!strcmp (p, "fpr") && key) 
357             rectype = RT_FPR;
358           else 
359             rectype = RT_NONE;
360         }
361       else if (rectype == RT_PUB || rectype == RT_SEC
362                || rectype == RT_CRT || rectype == RT_CRS)
363         {
364           switch (field)
365             {
366             case 2: /* trust info */
367               trust_info = p; 
368               set_mainkey_trust_info (key, trust_info);
369               break;
370             case 3: /* key length */
371               i = atoi (p); 
372               if (i > 1) /* ignore invalid values */
373                 key->keys.key_len = i; 
374                 break;
375             case 4: /* pubkey algo */
376               i = atoi (p);
377               if (i > 1 && i < 128)
378                 key->keys.key_algo = i;
379               break;
380               case 5: /* long keyid */
381                 if (strlen (p) == DIM(key->keys.keyid) - 1)
382                   strcpy (key->keys.keyid, p);
383                 break;
384             case 6: /* timestamp (seconds) */
385               key->keys.timestamp = parse_timestamp (p);
386               break;
387             case 7: /* expiration time (seconds) */
388               key->keys.expires_at = parse_timestamp (p);
389               break;
390             case 8: /* X.509 serial number */
391               if (rectype == RT_CRT)
392                 {
393                   key->issuer_serial = xtrystrdup (p);
394                   if (!key->issuer_serial)
395                     ctx->error = mk_error (Out_Of_Core);
396                 }
397               break;
398             case 9: /* ownertrust */
399               set_ownertrust (key, p);
400               break;
401             case 10: /* not used for gpg due to --fixed-list-mode option 
402                         but gpgsm stores the issuer name */
403               if (rectype == RT_CRT)
404                 {
405                   key->issuer_name = xtrystrdup (p);
406                   if (!key->issuer_name)
407                     ctx->error = mk_error (Out_Of_Core);
408                 }
409               break;
410             case 11: /* signature class  */
411               break;
412             case 12: /* capabilities */
413               set_mainkey_capability (key, p);
414               break;
415             case 13:
416               pend = NULL;  /* we can stop here */
417               break;
418             }
419           }
420         else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
421           {
422             switch (field)
423               {
424               case 2: /* trust info */
425                 set_subkey_trust_info (sk, p);
426                 break;
427               case 3: /* key length */
428                 i = atoi (p); 
429                 if (i > 1) /* ignore invalid values */
430                   sk->key_len = i; 
431                 break;
432               case 4: /* pubkey algo */
433                 i = atoi (p);
434                 if (i > 1 && i < 128)
435                   sk->key_algo = i;
436                 break;
437               case 5: /* long keyid */
438                 if (strlen (p) == DIM(sk->keyid) - 1)
439                   strcpy (sk->keyid, p);
440                 break;
441               case 6: /* timestamp (seconds) */
442                 sk->timestamp = parse_timestamp (p);
443                 break;
444               case 7: /* expiration time (seconds) */
445                 break;
446               case 8: /* reserved (LID) */
447                 break;
448               case 9: /* ownertrust */
449                 break;
450               case 10:/* user ID n/a for a subkey */
451                 break;
452               case 11:  /* signature class  */
453                 break;
454               case 12: /* capability */
455                 set_subkey_capability (sk, p);
456                 break;
457               case 13:
458                 pend = NULL;  /* we can stop here */
459                 break;
460             }
461         }
462       else if (rectype == RT_UID)
463         {
464           switch (field)
465             {
466             case 2: /* trust info */
467               trust_info = p;  /*save for later */
468               break;
469             case 10: /* user ID */
470               if (_gpgme_key_append_name (key, p))
471                 /* The only kind of error we can get*/
472                 ctx->error = mk_error (Out_Of_Core);
473               else
474                 {
475                   if (trust_info)
476                   set_userid_flags (key, trust_info);
477                 }
478               pend = NULL;  /* we can stop here */
479               break;
480             }
481         }
482       else if (rectype == RT_FPR)
483         {
484           switch (field)
485             {
486             case 10: /* fingerprint (take only the first one)*/
487               if (!key->keys.fingerprint && *p)
488                 {
489                   key->keys.fingerprint = xtrystrdup (p);
490                   if (!key->keys.fingerprint)
491                     ctx->error = mk_error (Out_Of_Core);
492                 }
493               break;
494             case 13: /* gpgsm chain ID (take only the first one)*/
495               if (!key->chain_id && *p)
496                 {
497                   key->chain_id = xtrystrdup (p);
498                   if (!key->chain_id)
499                     ctx->error = mk_error (Out_Of_Core);
500                 }
501               pend = NULL; /* that is all we want */
502               break;
503             }
504         }
505     }
506 }
507
508
509 /*
510  * We have read an entire key into ctx->tmp_key and should now finish
511  * it.  It is assumed that this releases ctx->tmp_key.
512  */
513 static void
514 finish_key (GpgmeCtx ctx)
515 {
516   GpgmeKey key = ctx->tmp_key;
517   struct key_queue_item_s *q, *q2;
518
519   if (key)
520     {
521       ctx->tmp_key = NULL;
522         
523       _gpgme_key_cache_add (key);
524         
525       q = xtrymalloc (sizeof *q);
526       if (!q)
527         {
528           gpgme_key_release (key);
529           ctx->error = mk_error (Out_Of_Core);
530           return;
531         }
532       q->key = key;
533       q->next = NULL;
534       /* FIXME: Lock queue.  Use a tail pointer?  */
535       if (!(q2 = ctx->key_queue))
536         ctx->key_queue = q;
537       else
538         {
539           for (; q2->next; q2 = q2->next)
540             ;
541           q2->next = q;
542         }
543       ctx->key_cond = 1;
544       /* FIXME: Unlock queue.  */
545     }
546 }
547
548
549 /**
550  * gpgme_op_keylist_start:
551  * @c: context 
552  * @pattern: a GnuPG user ID or NULL for all
553  * @secret_only: List only keys where the secret part is available
554  * 
555  * Note that this function also cancels a pending key listing
556  * operaton. To actually retrieve the key, use
557  * gpgme_op_keylist_next().
558  * 
559  * Return value:  0 on success or an errorcode. 
560  **/
561 GpgmeError
562 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
563 {
564   GpgmeError err = 0;
565
566   /* Keylist operations are always "synchronous" in the sense that we
567      don't add ourself to the global FD table.  */
568   err = _gpgme_op_reset (ctx, 1);
569   if (err)
570     goto leave;
571
572   gpgme_key_release (ctx->tmp_key);
573   ctx->tmp_key = NULL;
574   /* Fixme: Release key_queue.  */
575
576   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
577   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
578                                               keylist_colon_handler, ctx);
579   if (err)
580     goto leave;
581
582   /* We don't want to use the verbose mode as this will also print 
583      the key signatures which is in most cases not needed and furthermore we 
584      just ignore those lines - This should speed up things */
585   _gpgme_engine_set_verbosity (ctx->engine, 0);
586
587   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
588                                   ctx->keylist_mode);
589
590   if (!err)     /* And kick off the process.  */
591     err = _gpgme_engine_start (ctx->engine, ctx);
592
593  leave:
594   if (err)
595     {
596       ctx->pending = 0; 
597       _gpgme_engine_release (ctx->engine);
598       ctx->engine = NULL;
599     }
600   return err;
601 }
602
603
604 /**
605  * gpgme_op_keylist_ext_start:
606  * @c: context 
607  * @pattern: a NULL terminated array of search patterns
608  * @secret_only: List only keys where the secret part is available
609  * @reserved: Should be 0.
610  * 
611  * Note that this function also cancels a pending key listing
612  * operaton. To actually retrieve the key, use
613  * gpgme_op_keylist_next().
614  * 
615  * Return value:  0 on success or an errorcode. 
616  **/
617 GpgmeError
618 gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
619                             int secret_only, int reserved)
620 {
621   GpgmeError err = 0;
622
623   /* Keylist operations are always "synchronous" in the sense that we
624      don't add ourself to the global FD table.  */
625   err = _gpgme_op_reset (ctx, 1);
626   if (err)
627     goto leave;
628
629   gpgme_key_release (ctx->tmp_key);
630
631   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
632   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
633                                               keylist_colon_handler, ctx);
634   if (err)
635     goto leave;
636
637   /* We don't want to use the verbose mode as this will also print 
638      the key signatures which is in most cases not needed and furthermore we 
639      just ignore those lines - This should speed up things */
640   _gpgme_engine_set_verbosity (ctx->engine, 0);
641
642   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
643                                       reserved, ctx->keylist_mode);
644
645   if (!err)     /* And kick off the process.  */
646     err = _gpgme_engine_start (ctx->engine, ctx);
647
648  leave:
649   if (err)
650     {
651       ctx->pending = 0; 
652       _gpgme_engine_release (ctx->engine);
653       ctx->engine = NULL;
654     }
655   return err;
656 }
657
658
659 /**
660  * gpgme_op_keylist_next:
661  * @c: Context
662  * @r_key: Returned key object
663  * 
664  * Return the next key from the key listing started with
665  * gpgme_op_keylist_start().  The caller must free the key using
666  * gpgme_key_release().  If the last key has already been returned the
667  * last time the function was called, %GPGME_EOF is returned and the
668  * operation is finished.
669  * 
670  * Return value: 0 on success, %GPGME_EOF or another error code.
671  **/
672 GpgmeError
673 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
674 {
675   struct key_queue_item_s *queue_item;
676
677   if (!r_key)
678     return mk_error (Invalid_Value);
679   *r_key = NULL;
680   if (!ctx)
681     return mk_error (Invalid_Value);
682   if (!ctx->pending)
683     return mk_error (No_Request);
684   if (ctx->error)
685     return ctx->error;
686
687   if (!ctx->key_queue)
688     {
689       GpgmeError err = _gpgme_wait_on_condition (ctx, &ctx->key_cond);
690       if (err)
691         {
692           ctx->pending = 0;
693           return err;
694         }
695       if (!ctx->pending)
696         {
697           /* The operation finished.  Because not all keys might have
698              been returned to the caller yet, we just reset the
699              pending flag to 1.  This will cause us to call
700              _gpgme_wait_on_condition without any active file
701              descriptors, but that is a no-op, so it is safe.  */
702           ctx->pending = 1;
703         }
704       if (!ctx->key_cond)
705         {
706           ctx->pending = 0;
707           return mk_error (EOF);
708         }
709       ctx->key_cond = 0; 
710       assert (ctx->key_queue);
711     }
712   queue_item = ctx->key_queue;
713   ctx->key_queue = queue_item->next;
714   if (!ctx->key_queue)
715     ctx->key_cond = 0;
716   
717   *r_key = queue_item->key;
718   xfree (queue_item);
719   return 0;
720 }
721
722
723 /**
724  * gpgme_op_keylist_end:
725  * @c: Context
726  * 
727  * Ends the keylist operation and allows to use the context for some
728  * other operation next.
729  **/
730 GpgmeError
731 gpgme_op_keylist_end (GpgmeCtx ctx)
732 {
733   if (!ctx)
734     return mk_error (Invalid_Value);
735   if (!ctx->pending)
736     return mk_error (No_Request);
737   if (ctx->error)
738     return ctx->error;
739
740   ctx->pending = 0;
741   return 0;
742 }