2005-09-30 [paul] 1.9.14cvs63
[claws.git] / src / plugins / pgpcore / sgpgme.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2003 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
34 #include "sgpgme.h"
35 #include "privacy.h"
36 #include "prefs_common.h"
37 #include "utils.h"
38 #include "alertpanel.h"
39 #include "passphrase.h"
40 #include "prefs_gpg.h"
41 #include "select-keys.h"
42
43 static void sgpgme_disable_all(void)
44 {
45     /* FIXME: set a flag, so that we don't bother the user with failed
46      * gpgme messages */
47 }
48
49 gpgme_verify_result_t sgpgme_verify_signature(gpgme_ctx_t ctx, gpgme_data_t sig, 
50                                         gpgme_data_t plain, gpgme_data_t dummy)
51 {
52         gpgme_verify_result_t status = NULL;
53         gpgme_error_t err;
54
55         if ((err = gpgme_op_verify(ctx, sig, plain, dummy)) != GPG_ERR_NO_ERROR) {
56                 debug_print("op_verify err %s\n", gpgme_strerror(err));
57                 return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
58                 
59         }
60         status = gpgme_op_verify_result(ctx);
61
62         return status;
63 }
64
65 SignatureStatus sgpgme_sigstat_gpgme_to_privacy(gpgme_ctx_t ctx, gpgme_verify_result_t status)
66 {
67         unsigned long validity = 0;
68         gpgme_signature_t sig = NULL;
69         
70         if (GPOINTER_TO_INT(status) == -GPG_ERR_SYSTEM_ERROR) {
71                 debug_print("system error\n");
72                 return SIGNATURE_CHECK_FAILED;
73         }
74
75         if (status == NULL) {
76                 debug_print("status == NULL\n");
77                 return SIGNATURE_UNCHECKED;
78         }
79         sig = status->signatures;
80
81         if (sig == NULL) {
82                 debug_print("sig == NULL\n");
83                 return SIGNATURE_UNCHECKED;
84         }
85         validity = sig->validity;
86
87         debug_print("err code %d\n", gpg_err_code(sig->status));
88         switch (gpg_err_code(sig->status)) {
89         case GPG_ERR_NO_ERROR:
90                 if ((validity != GPGME_VALIDITY_MARGINAL) &&
91                     (validity != GPGME_VALIDITY_FULL) &&
92                     (validity != GPGME_VALIDITY_ULTIMATE))
93                         return SIGNATURE_WARN;
94                 return SIGNATURE_OK;
95         case GPG_ERR_SIG_EXPIRED:
96         case GPG_ERR_KEY_EXPIRED:
97                 return SIGNATURE_WARN;
98         case GPG_ERR_BAD_SIGNATURE:
99                 return SIGNATURE_INVALID;
100         case GPG_ERR_NO_PUBKEY:
101                 return SIGNATURE_CHECK_FAILED;
102         default:
103                 return SIGNATURE_CHECK_FAILED;
104         }
105         return SIGNATURE_CHECK_FAILED;
106 }
107
108 static const gchar *get_validity_str(unsigned long validity)
109 {
110         switch (gpg_err_code(validity)) {
111         case GPGME_VALIDITY_UNKNOWN:
112                 return _("Unknown");
113         case GPGME_VALIDITY_UNDEFINED:
114                 return _("Undefined");
115         case GPGME_VALIDITY_NEVER:
116                 return _("Never");
117         case GPGME_VALIDITY_MARGINAL:
118                 return _("Marginal");
119         case GPGME_VALIDITY_FULL:
120                 return _("Full");
121         case GPGME_VALIDITY_ULTIMATE:
122                 return _("Ultimate");
123         default:
124                 return _("Error");
125         }
126 }
127
128 static gchar *extract_name(const char *uid)
129 {
130         if (uid == NULL)
131                 return NULL;
132         if (!strncmp(uid, "CN=", 3)) {
133                 gchar *result = g_strdup(uid+3);
134                 if (strstr(result, ","))
135                         *(strstr(result, ",")) = '\0';
136                 return result;
137         } else if (strstr(uid, ",CN=")) {
138                 gchar *result = g_strdup(strstr(uid, ",CN=")+4);
139                 if (strstr(result, ","))
140                         *(strstr(result, ",")) = '\0';
141                 return result;
142         } else {
143                 return g_strdup(uid);
144         }
145 }
146 gchar *sgpgme_sigstat_info_short(gpgme_ctx_t ctx, gpgme_verify_result_t status)
147 {
148         gpgme_signature_t sig = NULL;
149         gchar *uname = NULL;
150         gpgme_key_t key;
151         gchar *result = NULL;
152
153         if (GPOINTER_TO_INT(status) == -GPG_ERR_SYSTEM_ERROR) {
154                 return g_strdup(_("The signature can't be checked - GPG error."));
155         }
156
157         if (status == NULL) {
158                 return g_strdup(_("The signature has not been checked."));
159         }
160         sig = status->signatures;
161         if (sig == NULL) {
162                 return g_strdup(_("The signature has not been checked."));
163         }
164
165         gpgme_get_key(ctx, sig->fpr, &key, 0);
166         if (key)
167                 uname = extract_name(key->uids->uid);
168         else
169                 uname = g_strdup("<?>");
170         switch (gpg_err_code(sig->status)) {
171         case GPG_ERR_NO_ERROR:
172                 result = g_strdup_printf(_("Good signature from %s (Trust: %s)."),
173                         uname, get_validity_str(sig->validity));
174                 break;
175         case GPG_ERR_SIG_EXPIRED:
176                 result = g_strdup_printf(_("Expired signature from %s."), uname);
177                 break;
178         case GPG_ERR_KEY_EXPIRED:
179                 result = g_strdup_printf(_("Expired key from %s."), uname);
180                 break;
181         case GPG_ERR_BAD_SIGNATURE:
182                 result = g_strdup_printf(_("Bad signature from %s."), uname);
183                 break;
184         case GPG_ERR_NO_PUBKEY:
185                 result = g_strdup(_("No key available to verify this signature."));
186                 break;
187         default:
188                 result = g_strdup(_("The signature has not been checked."));
189                 break;
190         }
191         if (result == NULL)
192                 result = g_strdup(_("Error"));
193         g_free(uname);
194         return result;
195 }
196
197 gchar *sgpgme_sigstat_info_full(gpgme_ctx_t ctx, gpgme_verify_result_t status)
198 {
199         gint i = 0;
200         gchar *ret;
201         GString *siginfo;
202         gpgme_signature_t sig = status->signatures;
203         
204         siginfo = g_string_sized_new(64);
205         while (sig) {
206                 gpgme_user_id_t user = NULL;
207                 gpgme_key_t key;
208
209                 const gchar *keytype, *keyid, *uid;
210                 
211                 gpgme_get_key(ctx, sig->fpr, &key, 0);
212
213                 if (key) {
214                         user = key->uids;
215                         keytype = gpgme_pubkey_algo_name(
216                                         key->subkeys->pubkey_algo);
217                         keyid = key->subkeys->keyid;
218                         uid = user->uid;
219                 } else {
220                         keytype = "?";
221                         keyid = "?";
222                         uid = "?";
223                 }
224                 g_string_append_printf(siginfo,
225                         _("Signature made using %s key ID %s\n"),
226                         keytype, keyid);
227                 
228                 switch (gpg_err_code(sig->status)) {
229                 case GPG_ERR_NO_ERROR:
230                 case GPG_ERR_KEY_EXPIRED:
231                         g_string_append_printf(siginfo,
232                                 _("Good signature from \"%s\"\n"),
233                                 uid);
234                         break;
235                 case GPG_ERR_SIG_EXPIRED:
236                         g_string_append_printf(siginfo,
237                                 _("Expired signature from \"%s\"\n"),
238                                 uid);
239                         break;
240                 case GPG_ERR_BAD_SIGNATURE:
241                         g_string_append_printf(siginfo,
242                                 _("BAD signature from \"%s\"\n"),
243                                 uid);
244                         break;
245                 default:
246                         break;
247                 }
248                 if (sig->status != GPG_ERR_BAD_SIGNATURE) {
249                         gint j = 1;
250                         user = user ? user->next : NULL;
251                         while (user != NULL) {
252                                 g_string_append_printf(siginfo,
253                                         _("                aka \"%s\"\n"),
254                                         user->uid);
255                                 j++;
256                                 user = user->next;
257                         }
258                         g_string_append_printf(siginfo,
259                                 _("Primary key fingerprint: %s\n"), 
260                                 sig ? sig->fpr: "?");
261                 }
262                 
263                 g_string_append(siginfo, "\n");
264                 i++;
265                 sig = sig->next;
266         }
267
268         ret = siginfo->str;
269         g_string_free(siginfo, FALSE);
270         return ret;
271 }
272
273 gpgme_data_t sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
274 {
275         gpgme_data_t data = NULL;
276         gpgme_error_t err;
277         FILE *fp = g_fopen(mimeinfo->data.filename, "rb");
278         gchar *tmp_file = NULL;
279
280         if (!fp) 
281                 return NULL;
282
283         tmp_file = get_tmp_file();
284         copy_file_part(fp, mimeinfo->offset, mimeinfo->length, tmp_file);
285         fclose(fp);
286         fp = g_fopen(tmp_file, "rb");
287         debug_print("tmp file %s\n", tmp_file);
288         if (!fp) 
289                 return NULL;
290         
291         err = gpgme_data_new_from_file(&data, tmp_file, 1);
292         g_unlink(tmp_file);
293         g_free(tmp_file);
294
295         debug_print("data %p (%d %d)\n", (void *)&data, mimeinfo->offset, mimeinfo->length);
296         if (err) {
297                 debug_print ("gpgme_data_new_from_file failed: %s\n",
298                              gpgme_strerror (err));
299                 return NULL;
300         }
301         return data;
302 }
303
304 gpgme_data_t sgpgme_decrypt_verify(gpgme_data_t cipher, gpgme_verify_result_t *status, gpgme_ctx_t ctx)
305 {
306         struct passphrase_cb_info_s info;
307         gpgme_data_t plain;
308         gpgme_error_t err;
309
310         memset (&info, 0, sizeof info);
311         
312         if (gpgme_data_new(&plain) != GPG_ERR_NO_ERROR) {
313                 gpgme_release(ctx);
314                 return NULL;
315         }
316         
317         if (!getenv("GPG_AGENT_INFO")) {
318                 info.c = ctx;
319                 gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
320         }
321
322         err = gpgme_op_decrypt_verify(ctx, cipher, plain);
323         if (err != GPG_ERR_NO_ERROR) {
324                 debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
325                 gpgmegtk_free_passphrase();
326                 gpgme_data_release(plain);
327                 return NULL;
328         }
329
330         err = gpgme_data_rewind(plain);
331         if (err) {
332                 debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
333         }
334
335         debug_print("decrypted.\n");
336         *status = gpgme_op_verify_result (ctx);
337
338         return plain;
339 }
340
341 gchar *sgpgme_get_encrypt_data(GSList *recp_names)
342 {
343         SelectionResult result = KEY_SELECTION_CANCEL;
344         gpgme_key_t *keys = gpgmegtk_recipient_selection(recp_names, &result);
345         gchar *ret = NULL;
346         int i = 0;
347
348         if (!keys) {
349                 if (result == KEY_SELECTION_DONT)
350                         return g_strdup("_DONT_ENCRYPT_");
351                 else
352                         return NULL;
353         }
354         while (keys[i]) {
355                 gpgme_subkey_t skey = keys[i]->subkeys;
356                 gchar *fpr = skey->fpr;
357                 gchar *tmp = NULL;
358                 debug_print("adding %s\n", fpr);
359                 tmp = g_strconcat(ret?ret:"", fpr, " ", NULL);
360                 g_free(ret);
361                 ret = tmp;
362                 i++;
363         }
364         return ret;
365 }
366
367 gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account)
368 {
369         GPGAccountConfig *config;
370
371         gpgme_signers_clear(ctx);
372
373         config = prefs_gpg_account_get_config(account);
374
375         if (config->sign_key != SIGN_KEY_DEFAULT) {
376                 gchar *keyid;
377                 gpgme_key_t key;
378
379                 if (config->sign_key == SIGN_KEY_BY_FROM)
380                         keyid = account->address;
381                 else if (config->sign_key == SIGN_KEY_CUSTOM)
382                         keyid = config->sign_key_id;
383                 else
384                         return FALSE;
385
386                 gpgme_op_keylist_start(ctx, keyid, 1);
387                 while (!gpgme_op_keylist_next(ctx, &key)) {
388                         gpgme_signers_add(ctx, key);
389                         gpgme_key_release(key);
390                 }
391                 gpgme_op_keylist_end(ctx);
392         }
393
394         prefs_gpg_account_free_config(config);
395
396         return TRUE;
397 }
398
399 void sgpgme_init()
400 {
401         gpgme_engine_info_t engineInfo;
402         if (gpgme_check_version("0.4.5")) {
403                 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
404                 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
405                 if (!gpgme_get_engine_info(&engineInfo)) {
406                         while (engineInfo) {
407                                 debug_print("GpgME Protocol: %s\n      Version: %s\n",
408                                         gpgme_get_protocol_name(engineInfo->protocol),
409                                         engineInfo->version);
410                                 engineInfo = engineInfo->next;
411                         }
412                 }
413         } else {
414                 sgpgme_disable_all();
415
416                 if (prefs_gpg_get_config()->gpg_warning) {
417                         AlertValue val;
418
419                         val = alertpanel_full
420                                 (_("Warning"),
421                                  _("GnuPG is not installed properly, or needs "
422                                  "to be upgraded.\n"
423                                  "OpenPGP support disabled."),
424                                  GTK_STOCK_CLOSE, NULL, NULL, TRUE, NULL,
425                                  ALERT_WARNING, G_ALERTDEFAULT);
426                         if (val & G_ALERTDISABLE)
427                                 prefs_gpg_get_config()->gpg_warning = FALSE;
428                 }
429         }
430 }
431
432 void sgpgme_done()
433 {
434         gpgmegtk_free_passphrase();
435 }
436
437 #endif /* USE_GPGME */