core,cpp: Extend the TOFU information.
[gpgme.git] / tests / run-keylist.c
1 /* run-keylist.c  - Helper to show a key listing.
2    Copyright (C) 2008, 2009 g10 Code GmbH
3
4    This file is part of GPGME.
5
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /* We need to include config.h so that we know whether we are building
21    with large file system (LFS) support. */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include <gpgme.h>
32
33 #define PGM "run-keylist"
34
35 #include "run-support.h"
36
37
38 static int verbose;
39
40
41 static int
42 show_usage (int ex)
43 {
44   fputs ("usage: " PGM " [options] [USERID]\n\n"
45          "Options:\n"
46          "  --verbose        run in verbose mode\n"
47          "  --openpgp        use the OpenPGP protocol (default)\n"
48          "  --cms            use the CMS protocol\n"
49          "  --secret         list only secret keys\n"
50          "  --local          use GPGME_KEYLIST_MODE_LOCAL\n"
51          "  --extern         use GPGME_KEYLIST_MODE_EXTERN\n"
52          "  --sigs           use GPGME_KEYLIST_MODE_SIGS\n"
53          "  --tofu           use GPGME_KEYLIST_MODE_TOFU\n"
54          "  --sig-notations  use GPGME_KEYLIST_MODE_SIG_NOTATIONS\n"
55          "  --ephemeral      use GPGME_KEYLIST_MODE_EPHEMERAL\n"
56          "  --validate       use GPGME_KEYLIST_MODE_VALIDATE\n"
57          "  --import         import all keys\n"
58          "  --offline        use offline mode\n"
59          "  --require-gnupg  required at least the given GnuPG version\n"
60          , stderr);
61   exit (ex);
62 }
63
64
65 static const char *
66 isotimestr (unsigned long value)
67 {
68   time_t t;
69   static char buffer[25+5];
70   struct tm *tp;
71
72   if (!value)
73     return "none";
74   t = value;
75
76   tp = gmtime (&t);
77   snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
78             1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
79             tp->tm_hour, tp->tm_min, tp->tm_sec);
80   return buffer;
81 }
82
83
84
85 int
86 main (int argc, char **argv)
87 {
88   int last_argc = -1;
89   gpgme_error_t err;
90   gpgme_ctx_t ctx;
91   gpgme_keylist_mode_t mode = 0;
92   gpgme_key_t key;
93   gpgme_subkey_t subkey;
94   gpgme_keylist_result_t result;
95   int import = 0;
96   gpgme_key_t keyarray[100];
97   int keyidx = 0;
98   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
99   int only_secret = 0;
100   int offline = 0;
101
102   if (argc)
103     { argc--; argv++; }
104
105   while (argc && last_argc != argc )
106     {
107       last_argc = argc;
108       if (!strcmp (*argv, "--"))
109         {
110           argc--; argv++;
111           break;
112         }
113       else if (!strcmp (*argv, "--help"))
114         show_usage (0);
115       else if (!strcmp (*argv, "--verbose"))
116         {
117           verbose = 1;
118           argc--; argv++;
119         }
120       else if (!strcmp (*argv, "--openpgp"))
121         {
122           protocol = GPGME_PROTOCOL_OpenPGP;
123           argc--; argv++;
124         }
125       else if (!strcmp (*argv, "--cms"))
126         {
127           protocol = GPGME_PROTOCOL_CMS;
128           argc--; argv++;
129         }
130       else if (!strcmp (*argv, "--secret"))
131         {
132           only_secret = 1;
133           argc--; argv++;
134         }
135       else if (!strcmp (*argv, "--local"))
136         {
137           mode |= GPGME_KEYLIST_MODE_LOCAL;
138           argc--; argv++;
139         }
140       else if (!strcmp (*argv, "--extern"))
141         {
142           mode |= GPGME_KEYLIST_MODE_EXTERN;
143           argc--; argv++;
144         }
145       else if (!strcmp (*argv, "--tofu"))
146         {
147           mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
148           argc--; argv++;
149         }
150       else if (!strcmp (*argv, "--sigs"))
151         {
152           mode |= GPGME_KEYLIST_MODE_SIGS;
153           argc--; argv++;
154         }
155       else if (!strcmp (*argv, "--sig-notations"))
156         {
157           mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
158           argc--; argv++;
159         }
160       else if (!strcmp (*argv, "--ephemeral"))
161         {
162           mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
163           argc--; argv++;
164         }
165       else if (!strcmp (*argv, "--validate"))
166         {
167           mode |= GPGME_KEYLIST_MODE_VALIDATE;
168           argc--; argv++;
169         }
170       else if (!strcmp (*argv, "--import"))
171         {
172           import = 1;
173           argc--; argv++;
174         }
175       else if (!strcmp (*argv, "--offline"))
176         {
177           offline = 1;
178           argc--; argv++;
179         }
180       else if (!strcmp (*argv, "--require-gnupg"))
181         {
182           argc--; argv++;
183           if (!argc)
184             show_usage (1);
185           gpgme_set_global_flag ("require-gnupg", *argv);
186           argc--; argv++;
187         }
188       else if (!strncmp (*argv, "--", 2))
189         show_usage (1);
190     }
191
192   if (argc > 1)
193     show_usage (1);
194
195   init_gpgme (protocol);
196
197   err = gpgme_new (&ctx);
198   fail_if_err (err);
199   gpgme_set_protocol (ctx, protocol);
200
201   gpgme_set_keylist_mode (ctx, mode);
202
203   gpgme_set_offline (ctx, offline);
204
205   err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret);
206   fail_if_err (err);
207
208   while (!(err = gpgme_op_keylist_next (ctx, &key)))
209     {
210       gpgme_user_id_t uid;
211       gpgme_tofu_info_t ti;
212       int nuids;
213       int nsub;
214
215       printf ("keyid   : %s\n", key->subkeys?nonnull (key->subkeys->keyid):"?");
216       printf ("fpr     : %s\n", key->subkeys?nonnull (key->subkeys->fpr):"?");
217       if (key->subkeys && key->subkeys->keygrip)
218         printf ("grip    : %s\n", key->subkeys->keygrip);
219       if (key->subkeys && key->subkeys->curve)
220             printf ("curve   : %s\n", key->subkeys->curve);
221       printf ("caps    : %s%s%s%s\n",
222               key->can_encrypt? "e":"",
223               key->can_sign? "s":"",
224               key->can_certify? "c":"",
225               key->can_authenticate? "a":"");
226       printf ("flags   :%s%s%s%s%s%s%s\n",
227               key->secret? " secret":"",
228               key->revoked? " revoked":"",
229               key->expired? " expired":"",
230               key->disabled? " disabled":"",
231               key->invalid? " invalid":"",
232               key->is_qualified? " qualifid":"",
233               key->subkeys && key->subkeys->is_cardkey? " cardkey":"");
234
235       subkey = key->subkeys;
236       if (subkey)
237         subkey = subkey->next;
238       for (nsub=1; subkey; subkey = subkey->next, nsub++)
239         {
240           printf ("fpr   %2d: %s\n", nsub, nonnull (subkey->fpr));
241           if (subkey->keygrip)
242             printf ("grip  %2d: %s\n", nsub, subkey->keygrip);
243           if (subkey->curve)
244             printf ("curve %2d: %s\n", nsub, subkey->curve);
245           printf ("caps  %2d: %s%s%s%s\n",
246                   nsub,
247                   subkey->can_encrypt? "e":"",
248                   subkey->can_sign? "s":"",
249                   subkey->can_certify? "c":"",
250                   subkey->can_authenticate? "a":"");
251           printf ("flags %2d:%s%s%s%s%s%s%s\n",
252                   nsub,
253                   subkey->secret? " secret":"",
254                   subkey->revoked? " revoked":"",
255                   subkey->expired? " expired":"",
256                   subkey->disabled? " disabled":"",
257                   subkey->invalid? " invalid":"",
258                   subkey->is_qualified? " qualifid":"",
259                   subkey->is_cardkey? " cardkey":"");
260         }
261       for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++)
262         {
263           printf ("userid %d: %s\n", nuids, nonnull(uid->uid));
264           printf ("    mbox: %s\n", nonnull(uid->address));
265           if (uid->email && uid->email != uid->address)
266             printf ("   email: %s\n", uid->email);
267           if (uid->name)
268             printf ("    name: %s\n", uid->name);
269           if (uid->comment)
270             printf ("   cmmnt: %s\n", uid->comment);
271           printf ("   valid: %s\n",
272                   uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
273                   uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
274                   uid->validity == GPGME_VALIDITY_NEVER? "never":
275                   uid->validity == GPGME_VALIDITY_MARGINAL? "marginal":
276                   uid->validity == GPGME_VALIDITY_FULL? "full":
277                   uid->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]");
278           if ((ti = uid->tofu))
279             {
280               printf ("    tofu: %u (%s)\n", ti->validity,
281                       ti->validity == 0? "conflict" :
282                       ti->validity == 1? "no history" :
283                       ti->validity == 2? "little history" :
284                       ti->validity == 3? "enough history" :
285                       ti->validity == 4? "lot of history" : "?");
286               printf ("  policy: %u (%s)\n", ti->policy,
287                       ti->policy == GPGME_TOFU_POLICY_NONE? "none" :
288                       ti->policy == GPGME_TOFU_POLICY_AUTO? "auto" :
289                       ti->policy == GPGME_TOFU_POLICY_GOOD? "good" :
290                       ti->policy == GPGME_TOFU_POLICY_UNKNOWN? "unknown" :
291                       ti->policy == GPGME_TOFU_POLICY_BAD? "bad" :
292                       ti->policy == GPGME_TOFU_POLICY_ASK? "ask" : "?");
293               printf ("   nsigs: %hu\n", ti->signcount);
294               printf ("   first: %s\n", isotimestr (ti->signfirst));
295               printf ("    last: %s\n", isotimestr (ti->signlast));
296               printf ("   nencr: %hu\n", ti->encrcount);
297               printf ("   first: %s\n", isotimestr (ti->encrfirst));
298               printf ("    last: %s\n", isotimestr (ti->encrlast));
299             }
300         }
301
302       putchar ('\n');
303
304       if (import)
305         {
306           if (keyidx < DIM (keyarray)-1)
307             keyarray[keyidx++] = key;
308           else
309             {
310               fprintf (stderr, PGM": too many keys in import mode"
311                        "- skipping this key\n");
312               gpgme_key_unref (key);
313             }
314         }
315       else
316         gpgme_key_unref (key);
317     }
318   if (gpgme_err_code (err) != GPG_ERR_EOF)
319     fail_if_err (err);
320   err = gpgme_op_keylist_end (ctx);
321   fail_if_err (err);
322   keyarray[keyidx] = NULL;
323
324   result = gpgme_op_keylist_result (ctx);
325   if (result->truncated)
326     {
327       fprintf (stderr, PGM ": key listing unexpectedly truncated\n");
328       exit (1);
329     }
330
331   if (import)
332     {
333       gpgme_import_result_t impres;
334
335       err = gpgme_op_import_keys (ctx, keyarray);
336       fail_if_err (err);
337       impres = gpgme_op_import_result (ctx);
338       if (!impres)
339         {
340           fprintf (stderr, PGM ": no import result returned\n");
341           exit (1);
342         }
343       print_import_result (impres);
344     }
345
346   for (keyidx=0; keyarray[keyidx]; keyidx++)
347     gpgme_key_unref (keyarray[keyidx]);
348
349   gpgme_release (ctx);
350   return 0;
351 }