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