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