Renamed to GNUPG
[gnupg.git] / g10 / g10.c
1 /* g10.c - The GNUPG utility (main for gpg)
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "packet.h"
29 #include "iobuf.h"
30 #include "memory.h"
31 #include "util.h"
32 #include "main.h"
33 #include "options.h"
34 #include "keydb.h"
35 #include "mpi.h"
36 #include "cipher.h"
37 #include "filter.h"
38 #include "trustdb.h"
39 #include "ttyio.h"
40 #include "i18n.h"
41 #include "status.h"
42
43
44 static ARGPARSE_OPTS opts[] = {
45
46     { 300, NULL, 0, N_("\vCommands:\n ") },
47
48     { 's', "sign",      0, N_("make a signature")},
49     { 539, "clearsign", 0, N_("make a clear text signature") },
50     { 'b', "detach-sign", 0, N_("make a detached signature")},
51     { 'e', "encrypt",   0, N_("encrypt data")},
52     { 'c', "symmetric", 0, N_("encryption only with symmetric cipher")},
53     { 507, "store",     0, N_("store only")},
54     { 'd', "decrypt",   0, N_("decrypt data (default)")},
55     { 'k', "list-keys", 0, N_("list keys")},
56     { 508, "check-keys",0, N_("check signatures on a key in the keyring")},
57     { 515, "fingerprint", 0, N_("show the fingerprints")},
58     { 521, "list-packets",0,N_("list only the sequence of packets")},
59     { 503, "gen-key",   0, N_("generate a new key pair")},
60     { 506, "sign-key"  ,0, N_("make a signature on a key in the keyring")},
61     { 505, "delete-key",0, N_("remove key from the public keyring")},
62     { 524, "edit-sig"  ,0, N_("edit a key signature")},
63     { 525, "change-passphrase", 0, N_("change the passphrase of your secret keyring")},
64     { 542, "gen-revoke",0, N_("generate a revocation certificate")},
65     { 537, "export"          , 0, N_("export keys") },
66     { 530, "import",      0     , N_("import/merge keys")},
67
68     { 301, NULL, 0, N_("\v\nOptions:\n ") },
69
70     { 'a', "armor",     0, N_("create ascii armored output")},
71     { 'o', "output",    2, N_("use as output file")},
72     { 'u', "local-user",2, N_("use this user-id to sign or decrypt")},
73     { 'r', "remote-user", 2, N_("use this user-id for encryption")},
74     { 'v', "verbose",   0, N_("verbose") },
75     { 'z', NULL,        1, N_("set compress level (0 disables)") },
76     { 't', "textmode",  0, N_("use canonical text mode")},
77     { 'n', "dry-run",   0, N_("don't make any changes") },
78     { 500, "batch",     0, N_("batch mode: never ask")},
79     { 501, "yes",       0, N_("assume yes on most questions")},
80     { 502, "no",        0, N_("assume no on most questions")},
81     { 509, "keyring"   ,2, N_("add this keyring to the list of keyrings")},
82     { 517, "secret-keyring" ,2, N_("add this secret keyring to the list")},
83     { 518, "options"   , 2, N_("read options from file")},
84
85     { 510, "debug"     ,4|16, N_("set debugging flags")},
86     { 511, "debug-all" ,0, N_("enable full debugging")},
87     { 512, "status-fd" ,1, N_("write status info to this fd") },
88     { 534, "no-comment", 0,   N_("do not write comment packets")},
89     { 535, "completes-needed", 1, N_("(default is 1)")},
90     { 536, "marginals-needed", 1, N_("(default is 3)")},
91     { 527, "cipher-algo", 2 , N_("select default cipher algorithm")},
92     { 528, "pubkey-algo", 2 , N_("select default puplic key algorithm")},
93     { 529, "digest-algo", 2 , N_("select default message digest algorithm")},
94
95     { 302, NULL, 0, N_("\v\nExamples:\n\n"
96     " -se -r Bob [file]          sign and encrypt for user Bob\n"
97     " -sat [file]                make a clear text signature\n"
98     " -sb  [file]                make a detached signature\n"
99     " -k   [userid]              show keys\n"
100     " -kc  [userid]              show fingerprint\n"  ) },
101
102   /* hidden options */
103     { 532, "quick-random", 0, "\r"},
104     { 526, "no-verbose", 0, "\r"},
105     { 538, "trustdb-name", 2, "\r" },
106     { 540, "no-secmem-warning", 0, "\r" }, /* used only by regression tests */
107     { 519, "no-armor",   0, "\r"},
108     { 520, "no-default-keyring", 0, "\r" },
109     { 522, "no-greeting", 0, "\r" },
110     { 523, "passphrase-fd",1, "\r" },
111     { 541, "no-operation", 0, "\r" },      /* used by regression tests */
112     { 543, "no-options", 0, "\r" }, /* shortcut for --options /dev/null */
113     { 544, "homedir", 2, "\r" },   /* defaults to "~/.gnupg" */
114     { 545, "no-batch", 0, "\r" },
115
116 {0} };
117
118
119
120
121 enum cmd_values { aNull = 0,
122     aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
123     aSignKey, aClearsign, aListPackets, aEditSig,
124     aKMode, aKModeC, aChangePass, aImport,
125     aExport, aCheckKeys, aGenRevoke,
126 aNOP };
127
128
129 static char *build_list( const char *text,
130                          const char *(*mapf)(int), int (*chkf)(int) );
131 static void set_cmd( enum cmd_values *ret_cmd,
132                         enum cmd_values new_cmd );
133
134 const char *
135 strusage( int level )
136 {
137   static char *digests, *pubkeys, *ciphers;
138     const char *p;
139     switch( level ) {
140       case 11: p = "GNUPG"; break;
141       case 13: p = VERSION; break;
142       case 17: p = PRINTABLE_OS_NAME; break;
143       case 19: p = _(
144 "Please report bugs to <gnupg-bugs@isil.d.shuttle.de>.\n"
145         ); break;
146       case 1:
147       case 40:  p = _(
148 "Usage: gpg [options] [files] (-h for help)"
149         ); break;
150       case 41:  p = _(
151 "Syntax: gpg [options] [files]\n"
152 "sign, check, encrypt or decrypt\n"
153 "default operation depends on the input data\n"
154         ); break;
155
156       case 31: p = "\n"; break;
157       case 32:
158         if( !ciphers )
159             ciphers = build_list("Supported ciphers: ", cipher_algo_to_string,
160                                                         check_cipher_algo );
161         p = ciphers;
162         break;
163       case 33:
164         if( !pubkeys )
165             pubkeys = build_list("Supported pubkeys: ", pubkey_algo_to_string,
166                                                         check_pubkey_algo );
167         p = pubkeys;
168         break;
169       case 34:
170         if( !digests )
171             digests = build_list("Supported digests: ", digest_algo_to_string,
172                                                         check_digest_algo );
173         p = digests;
174         break;
175
176       default:  p = default_strusage(level);
177     }
178     return p;
179 }
180
181
182 static char *
183 build_list( const char *text, const char * (*mapf)(int), int (*chkf)(int) )
184 {
185     int i;
186     const char *s;
187     size_t n=strlen(text)+2;
188     char *list, *p;
189
190     for(i=1; i < 100; i++ )
191         if( !chkf(i) && (s=mapf(i)) )
192             n += strlen(s) + 2;
193     list = m_alloc( 21 + n ); *list = 0;
194     for(p=NULL, i=1; i < 100; i++ ) {
195         if( !chkf(i) && (s=mapf(i)) ) {
196             if( !p )
197                 p = stpcpy( list, text );
198             else
199                 p = stpcpy( p, ", ");
200             p = stpcpy(p, s );
201         }
202     }
203     if( p )
204         p = stpcpy(p, "\n" );
205     return list;
206 }
207
208
209 static void
210 i18n_init(void)
211 {
212   #ifdef HAVE_LIBINTL
213     #ifdef HAVE_LC_MESSAGES
214        setlocale( LC_MESSAGES, "" );
215     #else
216        setlocale( LC_ALL, "" );
217     #endif
218     bindtextdomain( PACKAGE, G10_LOCALEDIR );
219     textdomain( PACKAGE );
220   #endif
221 }
222
223 static void
224 wrong_args( const char *text)
225 {
226     fputs(_("usage: gpg [options] "),stderr);
227     fputs(text,stderr);
228     putc('\n',stderr);
229     g10_exit(2);
230 }
231
232 static void
233 set_debug(void)
234 {
235     if( opt.debug & DBG_MEMORY_VALUE )
236         memory_debug_mode = 1;
237     if( opt.debug & DBG_MEMSTAT_VALUE )
238         memory_stat_debug_mode = 1;
239     if( opt.debug & DBG_MPI_VALUE )
240         mpi_debug_mode = 1;
241     if( opt.debug & DBG_CIPHER_VALUE )
242         cipher_debug_mode = 1;
243     if( opt.debug & DBG_IOBUF_VALUE )
244         iobuf_debug_mode = 1;
245 }
246
247
248 static void
249 set_cmd( enum cmd_values *ret_cmd, enum cmd_values new_cmd )
250 {
251     enum cmd_values cmd = *ret_cmd;
252
253     if( !cmd || cmd == new_cmd )
254         cmd = new_cmd;
255     else if( cmd == aSign && new_cmd == aEncr )
256         cmd = aSignEncr;
257     else if( cmd == aEncr && new_cmd == aSign )
258         cmd = aSignEncr;
259     else if( cmd == aKMode && new_cmd == aSym )
260         cmd = aKModeC;
261     else if(    ( cmd == aSign     && new_cmd == aClearsign )
262              || ( cmd == aClearsign && new_cmd == aSign )  )
263         cmd = aClearsign;
264     else {
265         log_error(_("conflicting commands\n"));
266         g10_exit(2);
267     }
268
269     *ret_cmd = cmd;
270 }
271
272
273
274 static void
275 check_opts(void)
276 {
277     if( !opt.def_cipher_algo || check_cipher_algo(opt.def_cipher_algo) )
278         log_error(_("selected cipher algorithm is invalid\n"));
279     if( !opt.def_pubkey_algo || check_pubkey_algo(opt.def_pubkey_algo) )
280         log_error(_("selected pubkey algorithm is invalid\n"));
281     if( !opt.def_digest_algo || check_digest_algo(opt.def_digest_algo) )
282         log_error(_("selected digest algorithm is invalid\n"));
283     if( opt.completes_needed < 1 )
284         log_error(_("completes-needed must be greater than 0\n"));
285     if( opt.marginals_needed < 2 )
286         log_error(_("marginals-needed must be greater than 1\n"));
287 }
288
289
290
291
292 void
293 main( int argc, char **argv )
294 {
295     ARGPARSE_ARGS pargs;
296     IOBUF a;
297     int rc=0;
298     int orig_argc;
299     char **orig_argv;
300     const char *fname, *fname_print;
301     STRLIST sl, remusr= NULL, locusr=NULL;
302     int nrings=0, sec_nrings=0;
303     armor_filter_context_t afx;
304     int detached_sig = 0;
305     FILE *configfp = NULL;
306     char *configname = NULL;
307     unsigned configlineno;
308     int parse_debug = 0;
309     int default_config =1;
310     int errors=0;
311     int default_keyring = 1;
312     int greeting = 1;
313     enum cmd_values cmd = 0;
314     const char *trustdb_name = NULL;
315
316     /* Please note that we may running SUID(ROOT), so be very CAREFUL
317      * when adding any stuff between here and the call to
318      * secmem_init()  somewhere after the option parsing
319      */
320
321     log_set_name("gpg");
322     i18n_init();
323     opt.compress = -1; /* defaults to standard compress level */
324     opt.def_cipher_algo = CIPHER_ALGO_BLOWFISH;
325     opt.def_pubkey_algo = PUBKEY_ALGO_ELGAMAL;
326     opt.def_digest_algo = DIGEST_ALGO_RMD160;
327     opt.completes_needed = 1;
328     opt.marginals_needed = 3;
329     opt.homedir = "~/.gnupg";
330
331     /* check wether we have a config file on the commandline */
332     orig_argc = argc;
333     orig_argv = argv;
334     pargs.argc = &argc;
335     pargs.argv = &argv;
336     pargs.flags=  1;  /* do not remove the args */
337     while( arg_parse( &pargs, opts) ) {
338         if( pargs.r_opt == 510 || pargs.r_opt == 511 )
339             parse_debug++;
340         else if( pargs.r_opt == 518 ) {
341             /* yes there is one, so we do not try the default one, but
342              * read the option file when it is encountered at the commandline
343              */
344             default_config = 0;
345         }
346         else if( pargs.r_opt == 543 )
347             default_config = 0; /* --no-options */
348         else if( pargs.r_opt == 544 )
349             opt.homedir = pargs.r.ret_str;
350     }
351
352     if( default_config )
353         configname = make_filename(opt.homedir, "options", NULL );
354
355     argc = orig_argc;
356     argv = orig_argv;
357     pargs.argc = &argc;
358     pargs.argv = &argv;
359     pargs.flags=  1;  /* do not remove the args */
360   next_pass:
361     if( configname ) {
362         configlineno = 0;
363         configfp = fopen( configname, "r" );
364         if( !configfp ) {
365             if( default_config ) {
366                 if( parse_debug )
367                     log_info(_("note: no default option file '%s'\n"),
368                                                             configname );
369             }
370             else {
371                 log_error(_("option file '%s': %s\n"),
372                                     configname, strerror(errno) );
373                 g10_exit(1);
374             }
375             m_free(configname); configname = NULL;
376         }
377         if( parse_debug && configname )
378             log_info(_("reading options from '%s'\n"), configname );
379         default_config = 0;
380     }
381
382     while( optfile_parse( configfp, configname, &configlineno,
383                                                 &pargs, opts) ) {
384         switch( pargs.r_opt ) {
385           case 'v': opt.verbose++; opt.list_sigs=1; break;
386           case 'z': opt.compress = pargs.r.ret_int; break;
387           case 'a': opt.armor = 1; opt.no_armor=0; break;
388           case 'd': break; /* it is default */
389           case 'c': set_cmd( &cmd , aSym); break;
390           case 'o': opt.outfile = pargs.r.ret_str; break;
391           case 'e': set_cmd( &cmd, aEncr); break;
392           case 'b': detached_sig = 1; /* fall trough */
393           case 's': set_cmd( &cmd, aSign );  break;
394           case 't': set_cmd( &cmd , aClearsign);  break;
395           case 'u': /* store the local users */
396             sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
397             strcpy(sl->d, pargs.r.ret_str);
398             sl->next = locusr;
399             locusr = sl;
400             break;
401           case 'r': /* store the remote users */
402             sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
403             strcpy(sl->d, pargs.r.ret_str);
404             sl->next = remusr;
405             remusr = sl;
406             break;
407           case 'k': set_cmd( &cmd, aKMode ); break;
408           case 500: opt.batch = 1; greeting = 0; break;
409           case 501: opt.answer_yes = 1; break;
410           case 502: opt.answer_no = 1; break;
411           case 503: set_cmd( &cmd, aKeygen); break;
412           case 506: set_cmd( &cmd, aSignKey); break;
413           case 507: set_cmd( &cmd, aStore); break;
414           case 508: set_cmd( &cmd, aCheckKeys);
415                     opt.check_sigs = 1; opt.list_sigs = 1; break;
416           case 509: add_keyring(pargs.r.ret_str); nrings++; break;
417           case 510: opt.debug |= pargs.r.ret_ulong; break;
418           case 511: opt.debug = ~0; break;
419           case 512: set_status_fd( pargs.r.ret_int ); break;
420           case 515: opt.fingerprint = 1; break;
421           case 517: add_secret_keyring(pargs.r.ret_str); sec_nrings++; break;
422           case 518:
423             /* config files may not be nested (silently ignore them) */
424             if( !configfp ) {
425                 m_free(configname);
426                 configname = m_strdup(pargs.r.ret_str);
427                 goto next_pass;
428             }
429             break;
430           case 519: opt.no_armor=1; opt.armor=0; break;
431           case 520: default_keyring = 0; break;
432           case 521: set_cmd( &cmd, aListPackets); break;
433           case 522: greeting = 0; break;
434           case 523: set_passphrase_fd( pargs.r.ret_int ); break;
435           case 524: set_cmd( &cmd, aEditSig); break;
436           case 525: set_cmd( &cmd, aChangePass); break;
437           case 526: opt.verbose = 0; opt.list_sigs=0; break;
438           case 527:
439             opt.def_cipher_algo = string_to_cipher_algo(pargs.r.ret_str);
440             break;
441           case 528:
442             opt.def_pubkey_algo = string_to_pubkey_algo(pargs.r.ret_str);
443             break;
444           case 529:
445             opt.def_digest_algo = string_to_digest_algo(pargs.r.ret_str);
446             break;
447           case 530: set_cmd( &cmd, aImport); break;
448           case 532: quick_random_gen(1); break;
449           case 534: opt.no_comment=1; break;
450           case 535: opt.completes_needed = pargs.r.ret_int; break;
451           case 536: opt.marginals_needed = pargs.r.ret_int; break;
452           case 537: set_cmd( &cmd, aExport); break;
453           case 538: trustdb_name = pargs.r.ret_str; break;
454           case 539: set_cmd( &cmd, aClearsign); break;
455           case 540: secmem_set_flags( secmem_get_flags() | 1 ); break;
456           case 541: set_cmd( &cmd, aNOP); break;
457           case 542: set_cmd( &cmd, aGenRevoke); break;
458           case 543: break; /* no-options */
459           case 544: opt.homedir = pargs.r.ret_str; break;
460           case 545: opt.batch = 0; break;
461           default : errors++; pargs.err = configfp? 1:2; break;
462         }
463     }
464     if( configfp ) {
465         fclose( configfp );
466         configfp = NULL;
467         m_free(configname); configname = NULL;
468         goto next_pass;
469     }
470     m_free( configname ); configname = NULL;
471     check_opts();
472     if( log_get_errorcount(0) )
473         g10_exit(2);
474
475     if( greeting ) {
476         tty_printf("%s %s; %s\n", strusage(11), strusage(13), strusage(14) );
477         tty_printf("%s\n", strusage(15) );
478     }
479
480     /* initialize the secure memory. */
481     secmem_init( 16384 );
482     /* Okay, we are now working under our real uid */
483
484     write_status( STATUS_ENTER );
485
486     set_debug();
487     if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */
488         if( cmd == aKModeC ) {
489             opt.fingerprint = 1;
490             cmd = aKMode;
491         }
492         opt.list_sigs = 0;
493         if( opt.verbose > 2 )
494             opt.check_sigs++;
495         if( opt.verbose > 1 )
496             opt.list_sigs++;
497
498         opt.verbose = opt.verbose > 1;
499     }
500     if( opt.verbose > 1 )
501         set_packet_list_mode(1);
502
503     if( !sec_nrings || default_keyring )  /* add default secret rings */
504         add_secret_keyring("secring.gpg");
505     if( !nrings || default_keyring )  /* add default ring */
506         add_keyring("pubring.gpg");
507
508     if( argc ) {
509         fname_print = fname = *argv;
510     }
511     else {
512         fname_print = "[stdin]";
513         fname = NULL;
514         if( get_passphrase_fd() == 0 ) {
515             /* reading data and passphrase form stdin:
516              * we assume the first line is the passphrase, so
517              * we read it now
518              */
519             /* FIXME: doit */
520         }
521     }
522
523     rc = init_trustdb(1, trustdb_name );
524     if( rc )
525         log_error(_("failed to initialize the TrustDB: %s\n"), g10_errstr(rc));
526
527
528     switch( cmd ) {
529       case aStore: /* only store the file */
530         if( argc > 1 )
531             wrong_args(_("--store [filename]"));
532         if( (rc = encode_store(fname)) )
533             log_error("%s: store failed: %s\n",
534                                     fname_print, g10_errstr(rc) );
535         break;
536
537       case aSym: /* encrypt the given file only with the symmetric cipher */
538         if( argc > 1 )
539             wrong_args(_("--symmetric [filename]"));
540         if( (rc = encode_symmetric(fname)) )
541             log_error("%s: symmetric encryption failed: %s\n", fname_print, g10_errstr(rc) );
542         break;
543
544       case aEncr: /* encrypt the given file */
545         if( argc > 1 )
546             wrong_args(_("--encrypt [filename]"));
547         if( (rc = encode_crypt(fname,remusr)) )
548             log_error("%s: encryption failed: %s\n", fname_print, g10_errstr(rc) );
549         break;
550
551       case aSign: /* sign the given file */
552         sl = NULL;
553         if( detached_sig ) { /* sign all files */
554             for( ; argc; argc--, argv++ )
555                 add_to_strlist( &sl, *argv );
556         }
557         else {
558             if( argc > 1 )
559                 wrong_args(_("--sign [filename]"));
560             if( argc ) {
561                 sl = m_alloc_clear( sizeof *sl + strlen(fname));
562                 strcpy(sl->d, fname);
563             }
564         }
565         if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) )
566             log_error("signing failed: %s\n", g10_errstr(rc) );
567         free_strlist(sl);
568         break;
569
570       case aSignEncr: /* sign and encrypt the given file */
571         if( argc > 1 )
572             wrong_args(_("--sign --encrypt [filename]"));
573         if( argc ) {
574             sl = m_alloc_clear( sizeof *sl + strlen(fname));
575             strcpy(sl->d, fname);
576         }
577         else
578             sl = NULL;
579         if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
580             log_error("%s: sign+encrypt failed: %s\n", fname_print, g10_errstr(rc) );
581         free_strlist(sl);
582         break;
583
584       case aClearsign: /* make a clearsig */
585         if( argc > 1 )
586             wrong_args(_("--clearsign [filename]"));
587         if( (rc = clearsign_file(fname, locusr, NULL)) )
588             log_error("%s: clearsign failed: %s\n", fname_print, g10_errstr(rc) );
589         break;
590
591
592       case aSignKey: /* sign the key given as argument */
593         if( argc != 1 )
594             wrong_args(_("--sign-key username"));
595         /* note: fname is the user id! */
596         if( (rc = sign_key(fname, locusr)) )
597             log_error("%s: sign key failed: %s\n", fname_print, g10_errstr(rc) );
598         break;
599
600       case aEditSig: /* Edit a key signature */
601         if( argc != 1 )
602             wrong_args(_("--edit-sig username"));
603         /* note: fname is the user id! */
604         if( (rc = edit_keysigs(fname)) )
605             log_error("%s: edit signature failed: %s\n", fname_print, g10_errstr(rc) );
606         break;
607
608       case aChangePass: /* Chnage the passphrase */
609         if( argc > 1 ) /* no arg: use default, 1 arg use this one */
610             wrong_args(_("--change-passphrase [username]"));
611         /* note: fname is the user id! */
612         if( (rc = change_passphrase(fname)) )
613             log_error("%s: change passphrase failed: %s\n", fname_print,
614                                                        g10_errstr(rc) );
615         break;
616
617       case aCheckKeys:
618       case aKMode: /* list keyring */
619         if( !argc ) { /* list the default public keyrings */
620             int i, seq=0;
621             const char *s;
622
623             while( (s=get_keyring(seq++)) ) {
624                 if( !(a = iobuf_open(s)) ) {
625                     log_error(_("can't open '%s'\n"), s);
626                     continue;
627                 }
628                 if( seq > 1 )
629                     putchar('\n');
630                 printf("%s\n", s );
631                 for(i=strlen(s); i; i-- )
632                     putchar('-');
633                 putchar('\n');
634
635                 proc_packets( a );
636                 iobuf_close(a);
637             }
638
639         }
640         else if( cmd == aCheckKeys ) {
641             log_error("will be soon: --check-keys user-ids\n");
642         }
643         else if( argc == 1) { /* list the given keyring */
644             if( !(a = iobuf_open(fname)) )
645                 log_error(_("can't open '%s'\n"), fname_print);
646             else {
647                 if( !opt.no_armor ) {
648                     memset( &afx, 0, sizeof afx);
649                     iobuf_push_filter( a, armor_filter, &afx );
650                 }
651                 proc_packets( a );
652                 iobuf_close(a);
653             }
654         }
655         else
656             wrong_args(_("-k[v][v][v][c] [keyring]") );
657         break;
658
659       case aKeygen: /* generate a key (interactive) */
660         if( argc )
661             wrong_args(_("--gen-key"));
662         generate_keypair();
663         break;
664
665       case aImport:
666         if( !argc  ) {
667             rc = import_pubkeys( NULL );
668             if( rc )
669                 log_error("import failed: %s\n", g10_errstr(rc) );
670         }
671         for( ; argc; argc--, argv++ ) {
672             rc = import_pubkeys( *argv );
673             if( rc )
674                 log_error("import from '%s' failed: %s\n",
675                                                 *argv, g10_errstr(rc) );
676         }
677         break;
678
679       case aExport:
680         sl = NULL;
681         for( ; argc; argc--, argv++ )
682             add_to_strlist( &sl, *argv );
683         export_pubkeys( sl );
684         free_strlist(sl);
685         break;
686
687       case aGenRevoke:
688         if( argc != 1 )
689             wrong_args("--gen-revoke user-id");
690         gen_revoke( *argv );
691         break;
692
693       case aNOP:
694         break;
695
696       case aListPackets:
697         opt.list_packets=1;
698       default:
699         if( argc > 1 )
700             wrong_args(_("[filename]"));
701         if( !(a = iobuf_open(fname)) )
702             log_error(_("can't open '%s'\n"), fname_print);
703         else {
704             if( !opt.no_armor ) {
705                 if( use_armor_filter( a ) ) {
706                     memset( &afx, 0, sizeof afx);
707                     iobuf_push_filter( a, armor_filter, &afx );
708                 }
709             }
710             if( cmd == aListPackets ) {
711                 set_packet_list_mode(1);
712                 opt.list_packets=1;
713             }
714             proc_packets( a );
715             iobuf_close(a);
716         }
717         break;
718     }
719
720     /* cleanup */
721     FREE_STRLIST(remusr);
722     FREE_STRLIST(locusr);
723     g10_exit(0);
724 }
725
726
727 void
728 g10_exit( int rc )
729 {
730     if( opt.debug )
731         secmem_dump_stats();
732     secmem_term();
733     rc = rc? rc : log_get_errorcount(0)? 2:0;
734     write_status( STATUS_LEAVE );
735     exit(rc );
736 }
737
738