2006-10-21 [paul] 2.5.6cvs4
[claws.git] / src / plugins / pgpcore / sgpgme.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2006 Hiroyuki Yamamoto & the Sylpheed-Claws team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19  
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23  
24 #ifdef USE_GPGME
25
26 #include <time.h>
27 #include <gtk/gtk.h>
28 #include <gpgme.h>
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__))
36 #  include <sys/signal.h>
37 #endif
38 #ifndef G_OS_WIN32
39 #include <sys/mman.h>
40 #endif
41 #if HAVE_LOCALE_H
42 #  include <locale.h>
43 #endif
44
45 #include "sgpgme.h"
46 #include "privacy.h"
47 #include "prefs_common.h"
48 #include "utils.h"
49 #include "alertpanel.h"
50 #include "passphrase.h"
51 #include "prefs_gpg.h"
52 #include "account.h"
53 #include "select-keys.h"
54
55 static void sgpgme_disable_all(void)
56 {
57     /* FIXME: set a flag, so that we don't bother the user with failed
58      * gpgme messages */
59 }
60
61 gpgme_verify_result_t sgpgme_verify_signature(gpgme_ctx_t ctx, gpgme_data_t sig, 
62                                         gpgme_data_t plain, gpgme_data_t dummy)
63 {
64         gpgme_verify_result_t status = NULL;
65         gpgme_error_t err;
66
67         if ((err = gpgme_op_verify(ctx, sig, plain, dummy)) != GPG_ERR_NO_ERROR) {
68                 debug_print("op_verify err %s\n", gpgme_strerror(err));
69                 privacy_set_error(gpgme_strerror(err));
70                 return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
71                 
72         }
73         status = gpgme_op_verify_result(ctx);
74
75         return status;
76 }
77
78 SignatureStatus sgpgme_sigstat_gpgme_to_privacy(gpgme_ctx_t ctx, gpgme_verify_result_t status)
79 {
80         unsigned long validity = 0;
81         gpgme_signature_t sig = NULL;
82         
83         if (GPOINTER_TO_INT(status) == -GPG_ERR_SYSTEM_ERROR) {
84                 debug_print("system error\n");
85                 return SIGNATURE_CHECK_FAILED;
86         }
87
88         if (status == NULL) {
89                 debug_print("status == NULL\n");
90                 return SIGNATURE_UNCHECKED;
91         }
92         sig = status->signatures;
93
94         if (sig == NULL) {
95                 debug_print("sig == NULL\n");
96                 return SIGNATURE_UNCHECKED;
97         }
98         validity = sig->validity;
99
100         debug_print("err code %d\n", gpg_err_code(sig->status));
101         switch (gpg_err_code(sig->status)) {
102         case GPG_ERR_NO_ERROR:
103                 switch (gpg_err_code(sig->validity)) {
104                 case GPGME_VALIDITY_NEVER:
105                         return SIGNATURE_INVALID;
106                 case GPGME_VALIDITY_UNKNOWN:
107                 case GPGME_VALIDITY_UNDEFINED:
108                 case GPGME_VALIDITY_MARGINAL:
109                 case GPGME_VALIDITY_FULL:
110                 case GPGME_VALIDITY_ULTIMATE:
111                         return SIGNATURE_OK;
112                 default:
113                         return SIGNATURE_CHECK_FAILED;
114                 }
115         case GPG_ERR_SIG_EXPIRED:
116         case GPG_ERR_KEY_EXPIRED:
117                 return SIGNATURE_WARN;
118         case GPG_ERR_BAD_SIGNATURE:
119                 return SIGNATURE_INVALID;
120         case GPG_ERR_NO_PUBKEY:
121                 return SIGNATURE_CHECK_FAILED;
122         default:
123                 return SIGNATURE_CHECK_FAILED;
124         }
125         return SIGNATURE_CHECK_FAILED;
126 }
127
128 static const gchar *get_validity_str(unsigned long validity)
129 {
130         switch (gpg_err_code(validity)) {
131         case GPGME_VALIDITY_UNKNOWN:
132                 return _("Unknown");
133         case GPGME_VALIDITY_UNDEFINED:
134                 return _("Undefined");
135         case GPGME_VALIDITY_NEVER:
136                 return _("Never");
137         case GPGME_VALIDITY_MARGINAL:
138                 return _("Marginal");
139         case GPGME_VALIDITY_FULL:
140                 return _("Full");
141         case GPGME_VALIDITY_ULTIMATE:
142                 return _("Ultimate");
143         default:
144                 return _("Error");
145         }
146 }
147
148 static gchar *extract_name(const char *uid)
149 {
150         if (uid == NULL)
151                 return NULL;
152         if (!strncmp(uid, "CN=", 3)) {
153                 gchar *result = g_strdup(uid+3);
154                 if (strstr(result, ","))
155                         *(strstr(result, ",")) = '\0';
156                 return result;
157         } else if (strstr(uid, ",CN=")) {
158                 gchar *result = g_strdup(strstr(uid, ",CN=")+4);
159                 if (strstr(result, ","))
160                         *(strstr(result, ",")) = '\0';
161                 return result;
162         } else {
163                 return g_strdup(uid);
164         }
165 }
166 gchar *sgpgme_sigstat_info_short(gpgme_ctx_t ctx, gpgme_verify_result_t status)
167 {
168         gpgme_signature_t sig = NULL;
169         gchar *uname = NULL;
170         gpgme_key_t key;
171         gchar *result = NULL;
172         gpgme_error_t err = 0;
173         static gboolean warned = FALSE;
174
175         if (GPOINTER_TO_INT(status) == -GPG_ERR_SYSTEM_ERROR) {
176                 return g_strdup_printf(_("The signature can't be checked - %s"), privacy_get_error());
177         }
178
179         if (status == NULL) {
180                 return g_strdup(_("The signature has not been checked."));
181         }
182         sig = status->signatures;
183         if (sig == NULL) {
184                 return g_strdup(_("The signature has not been checked."));
185         }
186
187         err = gpgme_get_key(ctx, sig->fpr, &key, 0);
188         if (gpg_err_code(err) == GPG_ERR_NO_AGENT) {
189                 if (!warned)
190                         alertpanel_error(_("PGP Core: Can't get key - no gpg-agent running."));
191                 else
192                         g_warning(_("PGP Core: Can't get key - no gpg-agent running."));
193                 warned = TRUE;
194         }
195         if (key)
196                 uname = extract_name(key->uids->uid);
197         else
198                 uname = g_strdup("<?>");
199         switch (gpg_err_code(sig->status)) {
200         case GPG_ERR_NO_ERROR:
201                 switch (gpg_err_code(sig->validity)) {
202                 case GPGME_VALIDITY_MARGINAL:
203                 case GPGME_VALIDITY_FULL:
204                 case GPGME_VALIDITY_ULTIMATE:
205                         result = g_strdup_printf(_("Good signature from %s."), uname);
206                         break;
207                 case GPGME_VALIDITY_UNKNOWN:
208                 case GPGME_VALIDITY_UNDEFINED:
209                 case GPGME_VALIDITY_NEVER:
210                 default:
211                         result = g_strdup_printf(_("Good signature (untrusted) from %s."), uname);
212                         break;
213                 }
214                 break;
215         case GPG_ERR_SIG_EXPIRED:
216                 result = g_strdup_printf(_("Expired signature from %s."), uname);
217                 break;
218         case GPG_ERR_KEY_EXPIRED:
219                 result = g_strdup_printf(_("Expired key from %s."), uname);
220                 break;
221         case GPG_ERR_BAD_SIGNATURE:
222                 result = g_strdup_printf(_("Bad signature from %s."), uname);
223                 break;
224         case GPG_ERR_NO_PUBKEY: {
225                 gchar *id = g_strdup(sig->fpr + strlen(sig->fpr)-8);
226                 result = g_strdup_printf(_("Key 0x%s not available to verify this signature."), id);
227                 g_free(id);
228                 break;
229                 }
230         default:
231                 result = g_strdup(_("The signature has not been checked."));
232                 break;
233         }
234         if (result == NULL)
235                 result = g_strdup(_("Error"));
236         g_free(uname);
237         return result;
238 }
239
240 gchar *sgpgme_sigstat_info_full(gpgme_ctx_t ctx, gpgme_verify_result_t status)
241 {
242         gint i = 0;
243         gchar *ret;
244         GString *siginfo;
245         gpgme_signature_t sig = status->signatures;
246         
247         siginfo = g_string_sized_new(64);
248         while (sig) {
249                 gpgme_user_id_t user = NULL;
250                 gpgme_key_t key;
251
252                 const gchar *keytype, *keyid, *uid;
253                 
254                 gpgme_get_key(ctx, sig->fpr, &key, 0);
255
256                 if (key) {
257                         user = key->uids;
258                         keytype = gpgme_pubkey_algo_name(
259                                         key->subkeys->pubkey_algo);
260                         keyid = key->subkeys->keyid;
261                         uid = user->uid;
262                 } else {
263                         keytype = "?";
264                         keyid = "?";
265                         uid = "?";
266                 }
267                 g_string_append_printf(siginfo,
268                         _("Signature made using %s key ID %s\n"),
269                         keytype, keyid);
270                 
271                 switch (gpg_err_code(sig->status)) {
272                 case GPG_ERR_NO_ERROR:
273                 case GPG_ERR_KEY_EXPIRED:
274                         g_string_append_printf(siginfo,
275                                 _("Good signature from \"%s\" (Trust: %s)\n"),
276                                 uid, get_validity_str(sig->validity));
277                         break;
278                 case GPG_ERR_SIG_EXPIRED:
279                         g_string_append_printf(siginfo,
280                                 _("Expired signature from \"%s\"\n"),
281                                 uid);
282                         break;
283                 case GPG_ERR_BAD_SIGNATURE:
284                         g_string_append_printf(siginfo,
285                                 _("BAD signature from \"%s\"\n"),
286                                 uid);
287                         break;
288                 default:
289                         break;
290                 }
291                 if (sig->status != GPG_ERR_BAD_SIGNATURE) {
292                         gint j = 1;
293                         user = user ? user->next : NULL;
294                         while (user != NULL) {
295                                 g_string_append_printf(siginfo,
296                                         _("                aka \"%s\"\n"),
297                                         user->uid);
298                                 j++;
299                                 user = user->next;
300                         }
301                         g_string_append_printf(siginfo,
302                                 _("Primary key fingerprint: %s\n"), 
303                                 sig ? sig->fpr: "?");
304 #ifdef HAVE_GPGME_PKA_TRUST
305                         if (sig->pka_trust == 1 && sig->pka_address) {
306                                 g_string_append_printf(siginfo,
307                                    _("WARNING: Signer's address \"%s\" "
308                                       "does not match DNS entry\n"), 
309                                    sig->pka_address);
310                         }
311                         else if (sig->pka_trust == 2 && sig->pka_address) {
312                                 g_string_append_printf(siginfo,
313                                    _("Verified signer's address is \"%s\"\n"),
314                                    sig->pka_address);
315                                 /* FIXME: Compare the address to the
316                                  * From: address.  */
317                         }
318 #endif /*HAVE_GPGME_PKA_TRUST*/
319                 }
320
321                 g_string_append(siginfo, "\n");
322                 i++;
323                 sig = sig->next;
324         }
325
326         ret = siginfo->str;
327         g_string_free(siginfo, FALSE);
328         return ret;
329 }
330
331 gpgme_data_t sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
332 {
333         gpgme_data_t data = NULL;
334         gpgme_error_t err;
335         FILE *fp = g_fopen(mimeinfo->data.filename, "rb");
336         gchar *tmp_file = NULL;
337
338         if (!fp) 
339                 return NULL;
340
341         tmp_file = get_tmp_file();
342         copy_file_part(fp, mimeinfo->offset, mimeinfo->length, tmp_file);
343         fclose(fp);
344         fp = NULL;
345         debug_print("tmp file %s\n", tmp_file);
346         
347         err = gpgme_data_new_from_file(&data, tmp_file, 1);
348         g_unlink(tmp_file);
349         g_free(tmp_file);
350
351         debug_print("data %p (%d %d)\n", (void *)&data, mimeinfo->offset, mimeinfo->length);
352         if (err) {
353                 debug_print ("gpgme_data_new_from_file failed: %s\n",
354                              gpgme_strerror (err));
355                 privacy_set_error(_("Couldn't get data from message, %s"), gpgme_strerror(err));
356                 return NULL;
357         }
358         return data;
359 }
360
361 gpgme_data_t sgpgme_decrypt_verify(gpgme_data_t cipher, gpgme_verify_result_t *status, gpgme_ctx_t ctx)
362 {
363         struct passphrase_cb_info_s info;
364         gpgme_data_t plain;
365         gpgme_error_t err;
366
367         memset (&info, 0, sizeof info);
368         
369         if ((err = gpgme_data_new(&plain)) != GPG_ERR_NO_ERROR) {
370                 gpgme_release(ctx);
371                 privacy_set_error(_("Couldn't initialize data, %s"), gpgme_strerror(err));
372                 return NULL;
373         }
374         
375         if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
376                 if (!getenv("GPG_AGENT_INFO")) {
377                         info.c = ctx;
378                         gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
379                 }
380         } else {
381                 info.c = ctx;
382                 gpgme_set_passphrase_cb (ctx, NULL, &info);
383         }
384         
385         
386         if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
387                 err = gpgme_op_decrypt_verify(ctx, cipher, plain);
388                 if (err != GPG_ERR_NO_ERROR) {
389                         debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
390                         privacy_set_error("%s", gpgme_strerror(err));
391                         gpgmegtk_free_passphrase();
392                         gpgme_data_release(plain);
393                         return NULL;
394                 }
395
396                 err = gpgme_data_rewind(plain);
397                 if (err) {
398                         debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
399                 }
400
401                 debug_print("decrypted.\n");
402                 *status = gpgme_op_verify_result (ctx);
403         } else {
404                 err = gpgme_op_decrypt(ctx, cipher, plain);
405                 if (err != GPG_ERR_NO_ERROR) {
406                         debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
407                         gpgmegtk_free_passphrase();
408                         gpgme_data_release(plain);
409                         return NULL;
410                 }
411
412                 err = gpgme_data_rewind(plain);
413                 if (err) {
414                         debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
415                 }
416
417                 debug_print("decrypted.\n");
418                 *status = gpgme_op_verify_result (ctx);
419         }
420         return plain;
421 }
422
423 gchar *sgpgme_get_encrypt_data(GSList *recp_names, gpgme_protocol_t proto)
424 {
425         SelectionResult result = KEY_SELECTION_CANCEL;
426         gpgme_key_t *keys = gpgmegtk_recipient_selection(recp_names, &result,
427                                 proto);
428         gchar *ret = NULL;
429         int i = 0;
430
431         if (!keys) {
432                 if (result == KEY_SELECTION_DONT)
433                         return g_strdup("_DONT_ENCRYPT_");
434                 else
435                         return NULL;
436         }
437         while (keys[i]) {
438                 gpgme_subkey_t skey = keys[i]->subkeys;
439                 gchar *fpr = skey->fpr;
440                 gchar *tmp = NULL;
441                 debug_print("adding %s\n", fpr);
442                 tmp = g_strconcat(ret?ret:"", fpr, " ", NULL);
443                 g_free(ret);
444                 ret = tmp;
445                 i++;
446         }
447         return ret;
448 }
449
450 gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account)
451 {
452         GPGAccountConfig *config;
453
454         gpgme_signers_clear(ctx);
455
456         config = prefs_gpg_account_get_config(account);
457
458         switch(config->sign_key) {
459         case SIGN_KEY_DEFAULT:
460                 debug_print("using default gnupg key\n");
461                 break;
462         case SIGN_KEY_BY_FROM:
463                 debug_print("using key for %s\n", account->address);
464                 break;
465         case SIGN_KEY_CUSTOM:
466                 debug_print("using key for %s\n", config->sign_key_id);
467                 break;
468         }
469
470         if (config->sign_key != SIGN_KEY_DEFAULT) {
471                 gchar *keyid;
472                 gpgme_key_t key, key2;
473                 gpgme_error_t err;
474
475                 if (config->sign_key == SIGN_KEY_BY_FROM)
476                         keyid = account->address;
477                 else if (config->sign_key == SIGN_KEY_CUSTOM)
478                         keyid = config->sign_key_id;
479                 else
480                         goto bail;
481
482                 err = gpgme_op_keylist_start(ctx, keyid, 1);
483                 if (!err)
484                         err = gpgme_op_keylist_next(ctx, &key);
485                 if (err) {
486                         g_warning("setup_signers start: %s", gpgme_strerror(err));
487                         privacy_set_error(_("Secret key not found (%s)"), gpgme_strerror(err));
488                         goto bail;
489                 }
490                 
491                 err = gpgme_op_keylist_next(ctx, &key2);
492                 if (!err) {
493                         g_warning("ambiguous specification of secret key '%s'\n",
494                                 keyid);
495                         privacy_set_error(_("Secret key specification is ambiguous"));
496                         goto bail;
497                 }
498                 
499                 gpgme_op_keylist_end(ctx);
500                 err = gpgme_signers_add(ctx, key);
501                 gpgme_key_release(key);
502                 
503                 if (err) {
504                         g_warning("error adding secret key: %s\n", gpgme_strerror(err));
505                         privacy_set_error(_("Error setting secret key: %s"), gpgme_strerror(err));
506                         goto bail;
507                 }
508         }
509
510         prefs_gpg_account_free_config(config);
511
512         return TRUE;
513 bail:
514         prefs_gpg_account_free_config(config);
515         return FALSE;
516 }
517
518 void sgpgme_init()
519 {
520         gpgme_engine_info_t engineInfo;
521         if (gpgme_check_version("1.0.0")) {
522 #ifdef LC_CTYPE
523                 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
524 #endif
525 #ifdef LC_MESSAGES
526                 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
527 #endif
528                 if (!gpgme_get_engine_info(&engineInfo)) {
529                         while (engineInfo) {
530                                 debug_print("GpgME Protocol: %s\n"
531                                             "Version: %s (req %s)\n"
532                                             "Executable: %s\n",
533                                         gpgme_get_protocol_name(engineInfo->protocol),
534                                         engineInfo->version ? engineInfo->version:"???",
535                                         engineInfo->req_version ? engineInfo->req_version:"???",
536                                         engineInfo->file_name ? engineInfo->file_name:"???");
537                                 if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP
538                                 &&  gpgme_engine_check_version(engineInfo->protocol) != 
539                                         GPG_ERR_NO_ERROR) {
540                                         if (engineInfo->file_name && !engineInfo->version) {
541                                                 alertpanel_error(_("Gpgme protocol '%s' is unusable: "
542                                                                    "Engine '%s' isn't installed properly."),
543                                                                    gpgme_get_protocol_name(engineInfo->protocol),
544                                                                    engineInfo->file_name);
545                                         } else if (engineInfo->file_name && engineInfo->version
546                                           && engineInfo->req_version) {
547                                                 alertpanel_error(_("Gpgme protocol '%s' is unusable: "
548                                                                    "Engine '%s' version %s is installed, "
549                                                                    "but version %s is required.\n"),
550                                                                    gpgme_get_protocol_name(engineInfo->protocol),
551                                                                    engineInfo->file_name,
552                                                                    engineInfo->version,
553                                                                    engineInfo->req_version);
554                                         } else {
555                                                 alertpanel_error(_("Gpgme protocol '%s' is unusable "
556                                                                    "(unknown problem)"),
557                                                                    gpgme_get_protocol_name(engineInfo->protocol));
558                                         }
559                                 }
560                                 engineInfo = engineInfo->next;
561                         }
562                 }
563         } else {
564                 sgpgme_disable_all();
565
566                 if (prefs_gpg_get_config()->gpg_warning) {
567                         AlertValue val;
568
569                         val = alertpanel_full
570                                 (_("Warning"),
571                                  _("GnuPG is not installed properly, or needs "
572                                  "to be upgraded.\n"
573                                  "OpenPGP support disabled."),
574                                  GTK_STOCK_CLOSE, NULL, NULL, TRUE, NULL,
575                                  ALERT_WARNING, G_ALERTDEFAULT);
576                         if (val & G_ALERTDISABLE)
577                                 prefs_gpg_get_config()->gpg_warning = FALSE;
578                 }
579         }
580 }
581
582 void sgpgme_done()
583 {
584         gpgmegtk_free_passphrase();
585 }
586
587 void sgpgme_create_secret_key(PrefsAccount *account, gboolean ask_create)
588 {
589         AlertValue val = G_ALERTDEFAULT;
590         gchar *key_parms = NULL;
591         gchar *name = NULL;
592         gchar *email = NULL;
593         gchar *passphrase = NULL, *passphrase_second = NULL;
594         gint prev_bad = 0;
595         gchar *tmp = NULL;
596         gpgme_error_t err = 0;
597         gpgme_ctx_t ctx;
598         GtkWidget *window = NULL;
599         gpgme_genkey_result_t key;
600
601         if (account == NULL)
602                 account = account_get_default();
603
604         if (account->address == NULL) {
605                 alertpanel_error(_("You have to save the account's information with \"OK\" "
606                                    "before being able to generate a key pair.\n"));
607                 return;
608         }
609         if (ask_create) {
610                 val = alertpanel(_("No PGP key found"),
611                                 _("Sylpheed-Claws did not find a secret PGP key, "
612                                   "which means that you won't be able to sign "
613                                   "emails or receive encrypted emails.\n"
614                                   "Do you want to create a new key pair now?"),
615                                   GTK_STOCK_NO, "+" GTK_STOCK_YES, NULL);
616                 if (val == G_ALERTDEFAULT) {
617                         prefs_gpg_get_config()->gpg_ask_create_key = FALSE;
618                         prefs_gpg_save_config();
619                         return;
620                 }
621         }
622
623         if (account->name) {
624                 name = g_strdup(account->name);
625         } else {
626                 name = g_strdup(account->address);
627         }
628         email = g_strdup(account->address);
629         tmp = g_strdup_printf("%s <%s>", account->name?account->name:account->address, account->address);
630 again:
631         passphrase = passphrase_mbox(tmp, NULL, prev_bad, 1);
632         if (passphrase == NULL) {
633                 g_free(tmp);
634                 g_free(email);
635                 g_free(name);           
636                 return;
637         }
638         passphrase_second = passphrase_mbox(tmp, NULL, 0, 2);
639         if (passphrase_second == NULL) {
640                 g_free(tmp);
641                 g_free(email);
642                 g_free(passphrase);             
643                 g_free(name);           
644                 return;
645         }
646         if (strcmp(passphrase, passphrase_second)) {
647                 g_free(passphrase);
648                 g_free(passphrase_second);
649                 prev_bad = 1;
650                 goto again;
651         }
652         
653         key_parms = g_strdup_printf("<GnupgKeyParms format=\"internal\">\n"
654                                         "Key-Type: DSA\n"
655                                         "Key-Length: 1024\n"
656                                         "Subkey-Type: ELG-E\n"
657                                         "Subkey-Length: 2048\n"
658                                         "Name-Real: %s\n"
659                                         "Name-Email: %s\n"
660                                         "Expire-Date: 0\n"
661                                         "%s%s%s"
662                                         "</GnupgKeyParms>\n",
663                                         name, email, 
664                                         strlen(passphrase)?"Passphrase: ":"",
665                                         passphrase,
666                                         strlen(passphrase)?"\n":"");
667 #ifndef G_PLATFORM_WIN32
668         if (mlock(passphrase, strlen(passphrase)) == -1)
669                 debug_print("couldn't lock passphrase\n");
670         if (mlock(passphrase_second, strlen(passphrase_second)) == -1)
671                 debug_print("couldn't lock passphrase2\n");
672 #endif
673         g_free(tmp);
674         g_free(email);
675         g_free(name);
676         g_free(passphrase_second);
677         g_free(passphrase);
678         
679         err = gpgme_new (&ctx);
680         if (err) {
681                 alertpanel_error(_("Couldn't generate a new key pair: %s"),
682                                  gpgme_strerror(err));
683                 g_free(key_parms);
684                 return;
685         }
686         
687
688         window = label_window_create(_("Generating your new key pair... Please move the mouse "
689                               "around to help generate entropy..."));
690
691         err = gpgme_op_genkey(ctx, key_parms, NULL, NULL);
692         g_free(key_parms);
693
694         gtk_widget_destroy(window);
695
696         if (err) {
697                 alertpanel_error(_("Couldn't generate a new key pair: %s"), gpgme_strerror(err));
698                 gpgme_release(ctx);
699                 return;
700         }
701         key = gpgme_op_genkey_result(ctx);
702         if (key == NULL) {
703                 alertpanel_error(_("Couldn't generate a new key pair: unknown error"));
704                 gpgme_release(ctx);
705                 return;
706         } else {
707                 gchar *buf = g_strdup_printf(_("Your new key pair has been generated. "
708                                     "Its fingerprint is:\n%s\n\nDo you want to export it "
709                                     "to a keyserver?"),
710                                     key->fpr ? key->fpr:"null");
711                 AlertValue val = alertpanel(_("Key generated"), buf,
712                                   GTK_STOCK_NO, "+" GTK_STOCK_YES, NULL);
713                 g_free(buf);
714                 if (val == G_ALERTALTERNATE) {
715 #ifndef G_OS_WIN32
716                         gchar *cmd = g_strdup_printf("gpg --no-tty --send-keys %s", key->fpr);
717                         int res = 0;
718                         pid_t pid = 0;
719                         pid = fork();
720                         if (pid == -1) {
721                                 res = -1;
722                         } else if (pid == 0) {
723                                 /* son */
724                                 res = system(cmd);
725                                 res = WEXITSTATUS(res);
726                                 _exit(res);
727                         } else {
728                                 int status = 0;
729                                 time_t start_wait = time(NULL);
730                                 res = -1;
731                                 do {
732                                         if (waitpid(pid, &status, WNOHANG) == 0 || !WIFEXITED(status)) {
733                                                 usleep(200000);
734                                         } else {
735                                                 res = WEXITSTATUS(status);
736                                                 break;
737                                         }
738                                         if (time(NULL) - start_wait > 5) {
739                                                 debug_print("SIGTERM'ing gpg\n");
740                                                 kill(pid, SIGTERM);
741                                         }
742                                         if (time(NULL) - start_wait > 6) {
743                                                 debug_print("SIGKILL'ing gpg\n");
744                                                 kill(pid, SIGKILL);
745                                                 break;
746                                         }
747                                 } while(1);
748                         }
749                         if (res == 0) {
750                                 alertpanel_notice(_("Key exported."));
751                         } else {
752                                 alertpanel_error(_("Couldn't export key."));
753                         }
754                         g_free(cmd);
755 #else
756                         alertpanel_error(_("Key export isn't implemented in Windows."));
757 #endif
758                 }
759         }
760         prefs_gpg_get_config()->gpg_ask_create_key = FALSE;
761         prefs_gpg_save_config();
762         gpgme_release(ctx);
763 }
764
765 gboolean sgpgme_has_secret_key(void)
766 {
767         gpgme_error_t err = 0;
768         gpgme_ctx_t ctx;
769         gpgme_key_t key;
770
771         err = gpgme_new (&ctx);
772         if (err) {
773                 debug_print("err : %s\n", gpgme_strerror(err));
774                 return TRUE;
775         }
776         err = gpgme_op_keylist_start(ctx, NULL, TRUE);
777         if (!err)
778                 err = gpgme_op_keylist_next(ctx, &key);
779         gpgme_op_keylist_end(ctx);
780         gpgme_release(ctx);
781         if (gpg_err_code(err) == GPG_ERR_EOF)
782                 return FALSE;
783         else
784                 return TRUE;
785 }
786
787 void sgpgme_check_create_key(void)
788 {
789         if (prefs_gpg_get_config()->gpg_ask_create_key &&
790             !sgpgme_has_secret_key()) {
791                 sgpgme_create_secret_key(NULL, TRUE);
792         } else {
793                 prefs_gpg_get_config()->gpg_ask_create_key = FALSE;
794                 prefs_gpg_save_config();
795         }       
796 }
797 #endif /* USE_GPGME */