Release 0.2.1
[gpgme.git] / gpgme / genkey.c
1 /* genkey.c -  key generation
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001 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 <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32 static void
33 genkey_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
34 {
35     if ( code == STATUS_PROGRESS && *args ) {
36         if (ctx->progress_cb) {
37             char *p;
38             int type=0, current=0, total=0;
39             
40             if ( (p = strchr (args, ' ')) ) {
41                 *p++ = 0;
42                 if (*p) {
43                     type = *(byte*)p;
44                     if ( (p = strchr (p+1, ' ')) ) {
45                         *p++ = 0;
46                         if (*p) {
47                             current = atoi (p);
48                             if ( (p = strchr (p+1, ' ')) ) {
49                                 *p++ = 0;
50                                 total = atoi (p);
51                             }
52                         }
53                     }
54                 }
55             }           
56             if ( type != 'X' )
57                 ctx->progress_cb ( ctx->progress_cb_value, args, type,
58                                    current, total );
59         }
60         return;
61     }
62
63     DEBUG2 ("genkey_status: code=%d args=`%s'\n", code, args );
64     /* FIXME: Need to do more */
65 }
66
67
68
69 /* 
70  * Here is how the parms should be formatted:
71 <GnupgKeyParms format="internal">
72 Key-Type: DSA
73 Key-Length: 1024
74 Subkey-Type: ELG-E
75 Subkey-Length: 1024
76 Name-Real: Joe Tester
77 Name-Comment: with stupid passphrase
78 Name-Email: joe@foo.bar
79 Expire-Date: 0
80 Passphrase: abc
81 </GnupgKeyParms>
82  * Strings should be given in UTF-8 encoding.  The format we support for now
83  * "internal".  The content of the <GnupgKeyParms> container is passed 
84  * verbatim to GnuPG.  Control statements (e.g. %pubring) are not allowed.
85  */
86
87 GpgmeError
88 gpgme_op_genkey_start ( GpgmeCtx c, const char *parms,
89                         GpgmeData pubkey, GpgmeData seckey )
90 {
91     int rc = 0;
92     int i;
93     const char *s, *s2, *sx;
94
95     fail_on_pending_request( c );
96     c->pending = 1;
97
98     gpgme_data_release (c->help_data_1); c->help_data_1 = NULL;
99
100     /* create a process object */
101     _gpgme_gpg_release (c->gpg); c->gpg = NULL;
102     rc = _gpgme_gpg_new ( &c->gpg );
103     if (rc)
104         goto leave;
105
106     /* We need a special mechanism to get the fd of a pipe here, so
107      * that we can use this for the %pubring and %secring parameters.
108      * We don't have this yet, so we implement only the adding to the
109      * standard keyrings */
110     if ( pubkey || seckey ) {
111         rc = mk_error (Not_Implemented);
112         goto leave;
113     }
114
115     _gpgme_gpg_set_status_handler ( c->gpg, genkey_status_handler, c );
116
117     /* build the commandline */
118     _gpgme_gpg_add_arg ( c->gpg, "--gen-key" );
119     if ( c->use_armor )
120         _gpgme_gpg_add_arg ( c->gpg, "--armor" );
121     for ( i=0; i < c->verbosity; i++ )
122         _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
123
124     if ( !pubkey && !seckey )
125         ; /* okay: Add key to the keyrings */
126     else if ( !pubkey
127               || gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE ) {
128         rc = mk_error (Invalid_Value);
129         goto leave;
130     }
131     else if ( !seckey
132               || gpgme_data_get_type (seckey) != GPGME_DATA_TYPE_NONE ) {
133         rc = mk_error (Invalid_Value);
134         goto leave;
135     }
136     
137     if ( pubkey ) {
138         _gpgme_data_set_mode (pubkey, GPGME_DATA_MODE_IN );
139         _gpgme_data_set_mode (seckey, GPGME_DATA_MODE_IN );
140         /* need some more things here */
141     }
142
143
144     if ( (parms = strstr (parms, "<GnupgKeyParms ")) 
145          && (s = strchr (parms, '>'))
146          && (sx = strstr (parms, "format=\"internal\""))
147          && sx < s
148          && (s2 = strstr (s+1, "</GnupgKeyParms>")) ) {
149         /* fixme: check that there are no control statements inside */
150         rc = gpgme_data_new_from_mem ( &c->help_data_1, s+1, s2-s-1, 1 );
151     }
152     else 
153         rc = mk_error (Invalid_Value);
154
155     if (rc )
156         goto leave;
157     
158     _gpgme_data_set_mode (c->help_data_1, GPGME_DATA_MODE_OUT );
159     _gpgme_gpg_add_data (c->gpg, c->help_data_1, 0);
160
161     rc = _gpgme_gpg_spawn ( c->gpg, c );
162     
163  leave:
164     if (rc) {
165         c->pending = 0; 
166         _gpgme_gpg_release ( c->gpg ); c->gpg = NULL;
167     }
168     return rc;
169 }
170
171
172
173 /**
174  * gpgme_op_genkey:
175  * @c: the context
176  * @parms: XML string with the key parameters
177  * @pubkey: Returns the public key
178  * @seckey: Returns the secret key
179  * 
180  * Generate a new key and store the key in the default keyrings if both
181  * @pubkey and @seckey are NULL.  If @pubkey and @seckey are given, the newly
182  * created key will be returned in these data objects.
183  * See gpgme_op_genkey_start() for a description of @parms.
184  * 
185  * Return value: 0 for success or an error code
186  **/
187 GpgmeError
188 gpgme_op_genkey( GpgmeCtx c, const char *parms,
189                  GpgmeData pubkey, GpgmeData seckey )
190 {
191     int rc = gpgme_op_genkey_start ( c, parms, pubkey, seckey );
192     if ( !rc ) {
193         gpgme_wait (c, 1);
194         c->pending = 0;
195     }
196     return rc;
197 }
198
199
200
201
202