2004-12-17 [martin] 0.9.13cvs17.2
[claws.git] / src / plugins / pgpmime / 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
30 #include "sgpgme.h"
31 #include "privacy.h"
32 #include "prefs_common.h"
33 #include "utils.h"
34 #include "alertpanel.h"
35 #include "passphrase.h"
36 #include "intl.h"
37 #include "prefs_gpg.h"
38 #include "select-keys.h"
39
40 static void idle_function_for_gpgme(void)
41 {
42         while (gtk_events_pending())
43                 gtk_main_iteration();
44 }
45
46 static void sgpgme_disable_all(void)
47 {
48     /* FIXME: set a flag, so that we don't bother the user with failed
49      * gpgme messages */
50 }
51
52 GpgmeSigStat sgpgme_verify_signature(GpgmeCtx ctx, GpgmeData sig, 
53                                         GpgmeData plain)
54 {
55         GpgmeSigStat status;
56
57         if (gpgme_op_verify(ctx, sig, plain, &status) != GPGME_No_Error)
58                 return GPGME_SIG_STAT_ERROR;
59
60         return status;
61 }
62
63 SignatureStatus sgpgme_sigstat_gpgme_to_privacy(GpgmeCtx ctx, GpgmeSigStat status)
64 {
65         unsigned long validity = 0;
66         
67         validity = gpgme_get_sig_ulong_attr(ctx, 0,
68                 GPGME_ATTR_VALIDITY, 0);
69
70         switch (status) {
71         case GPGME_SIG_STAT_GOOD:
72                 if ((validity != GPGME_VALIDITY_MARGINAL) &&
73                     (validity != GPGME_VALIDITY_FULL) &&
74                     (validity != GPGME_VALIDITY_ULTIMATE))
75                         return SIGNATURE_WARN;
76                 return SIGNATURE_OK;
77         case GPGME_SIG_STAT_GOOD_EXP:
78         case GPGME_SIG_STAT_GOOD_EXPKEY:
79         case GPGME_SIG_STAT_DIFF:
80                 return SIGNATURE_WARN;
81         case GPGME_SIG_STAT_BAD:
82                 return SIGNATURE_INVALID;
83         case GPGME_SIG_STAT_NOKEY:
84         case GPGME_SIG_STAT_NOSIG:
85         case GPGME_SIG_STAT_ERROR:
86                 return SIGNATURE_CHECK_FAILED;
87         case GPGME_SIG_STAT_NONE:
88                 return SIGNATURE_UNCHECKED;
89         }
90         return SIGNATURE_CHECK_FAILED;
91 }
92
93 static const gchar *get_validity_str(unsigned long validity)
94 {
95         switch (validity) {
96         case GPGME_VALIDITY_UNKNOWN:
97                 return _("Unknown");
98         case GPGME_VALIDITY_UNDEFINED:
99                 return _("Undefined");
100         case GPGME_VALIDITY_NEVER:
101                 return _("Never");
102         case GPGME_VALIDITY_MARGINAL:
103                 return _("Marginal");
104         case GPGME_VALIDITY_FULL:
105                 return _("Full");
106         case GPGME_VALIDITY_ULTIMATE:
107                 return _("Ultimate");
108         default:
109                 return _("Error");
110         }
111 }
112
113 gchar *sgpgme_sigstat_info_short(GpgmeCtx ctx, GpgmeSigStat status)
114 {
115         switch (status) {
116         case GPGME_SIG_STAT_GOOD:
117         {
118                 GpgmeKey key;
119                 unsigned long validity = 0;
120         
121                 if (gpgme_get_sig_key(ctx, 0, &key) != GPGME_No_Error)
122                         return g_strdup(_("Error"));
123
124                 validity = gpgme_get_sig_ulong_attr(ctx, 0,
125                         GPGME_ATTR_VALIDITY, 0);
126                 
127                 return g_strdup_printf(_("Valid signature by %s (Trust: %s)"),
128                         gpgme_key_get_string_attr(key, GPGME_ATTR_NAME, NULL, 0),
129                         get_validity_str(validity));
130         }
131         case GPGME_SIG_STAT_GOOD_EXP:
132                 return g_strdup(_("The signature has expired"));
133         case GPGME_SIG_STAT_GOOD_EXPKEY:
134                 return g_strdup(_("The key that was used to sign this part has expired"));
135         case GPGME_SIG_STAT_DIFF:
136                 return g_strdup(_("Not all signatures are valid"));
137         case GPGME_SIG_STAT_BAD:
138                 return g_strdup(_("This signature is invalid"));
139         case GPGME_SIG_STAT_NOKEY:
140                 return g_strdup(_("You have no key to verify this signature"));
141         case GPGME_SIG_STAT_NOSIG:
142                 return g_strdup(_("No signature found"));
143         case GPGME_SIG_STAT_ERROR:
144                 return g_strdup(_("An error occured"));
145         case GPGME_SIG_STAT_NONE:
146                 return g_strdup(_("The signature has not been checked"));
147         }
148         return g_strdup(_("Error"));
149 }
150
151 gchar *sgpgme_sigstat_info_full(GpgmeCtx ctx, GpgmeSigStat status)
152 {
153         gint i = 0;
154         gchar *ret;
155         GString *siginfo;
156         GpgmeKey key;
157         
158         siginfo = g_string_sized_new(64);
159         while (gpgme_get_sig_key(ctx, i, &key) != GPGME_EOF) {
160                 time_t sigtime, expiretime;
161                 GpgmeSigStat sigstatus;
162                 gchar timestr[64];
163                 const gchar *keytype, *keyid, *uid;
164                 
165                 sigtime = gpgme_get_sig_ulong_attr(ctx, i, GPGME_ATTR_CREATED, 0);
166                 strftime(timestr, 64, "%c", gmtime(&sigtime));
167                 keytype = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, NULL, 0);
168                 keyid = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, NULL, 0);
169                 g_string_append_printf(siginfo,
170                         _("Signature made %s using %s key ID %s\n"),
171                         timestr, keytype, keyid);
172                 
173                 sigstatus = gpgme_get_sig_ulong_attr(ctx, i, GPGME_ATTR_SIG_STATUS, 0); 
174                 uid = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, NULL, 0);
175                 switch (sigstatus) {
176                 case GPGME_SIG_STAT_GOOD:
177                 case GPGME_SIG_STAT_GOOD_EXPKEY:
178                         g_string_append_printf(siginfo,
179                                 _("Good signature from \"%s\"\n"),
180                                 uid);
181                         break;
182                 case GPGME_SIG_STAT_GOOD_EXP:
183                         g_string_append_printf(siginfo,
184                                 _("Expired signature from \"%s\"\n"),
185                                 uid);
186                         break;
187                 case GPGME_SIG_STAT_BAD:
188                         g_string_append_printf(siginfo,
189                                 _("BAD signature from \"%s\"\n"),
190                                 uid);
191                         break;
192                 default:
193                         break;
194                 }
195                 if (sigstatus != GPGME_SIG_STAT_BAD) {
196                         gint j = 1;
197                         
198                         while ((uid = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, NULL, j)) != 0) {
199                                 g_string_append_printf(siginfo,
200                                         _("                aka \"%s\"\n"),
201                                         uid);
202                                 j++;
203                         }
204                         g_string_append_printf(siginfo,
205                                 _("Primary key fingerprint: %s\n"), 
206                                 gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, NULL, 0));
207                 }
208
209                 
210                 expiretime = gpgme_get_sig_ulong_attr(ctx, i, GPGME_ATTR_EXPIRE, 0);
211                 if (expiretime > 0) {
212                         const gchar *format;
213
214                         strftime(timestr, 64, "%c", gmtime(&expiretime));
215                         if (time(NULL) < expiretime)
216                                 format = _("Signature expires %s\n");
217                         else
218                                 format = _("Signature expired %s\n");
219                         g_string_append_printf(siginfo, format, timestr);
220                 }
221                 
222                 g_string_append(siginfo, "\n");
223                 i++;
224         }
225
226         ret = siginfo->str;
227         g_string_free(siginfo, FALSE);
228         return ret;
229 }
230
231 GpgmeData sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
232 {
233         GpgmeData data;
234         
235         gpgme_data_new_from_filepart(&data,
236                 mimeinfo->data.filename,
237                 NULL,
238                 mimeinfo->offset,
239                 mimeinfo->length);
240         
241         return data;
242 }
243
244 GpgmeData sgpgme_decrypt_verify(GpgmeData cipher, GpgmeSigStat *status, GpgmeCtx ctx)
245 {
246         struct passphrase_cb_info_s info;
247         GpgmeData plain;
248         GpgmeError err;
249
250         memset (&info, 0, sizeof info);
251         
252         if (gpgme_data_new(&plain) != GPGME_No_Error) {
253                 gpgme_release(ctx);
254                 return NULL;
255         }
256         
257         if (!getenv("GPG_AGENT_INFO")) {
258                 info.c = ctx;
259                 gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
260         }
261
262         err = gpgme_op_decrypt_verify(ctx, cipher, plain, status);
263
264         if (err != GPGME_No_Error) {
265                 gpgmegtk_free_passphrase();
266                 gpgme_data_release(plain);
267                 return NULL;
268         }
269
270         return plain;
271 }
272
273 gchar *sgpgme_get_encrypt_data(GSList *recp_names)
274 {
275
276         GpgmeRecipients recp;
277         GString *encdata;
278         void *iter;
279         const gchar *recipient;
280         gchar *data;
281
282         recp = gpgmegtk_recipient_selection(recp_names);
283         if (recp == NULL)
284                 return NULL;
285
286         if (gpgme_recipients_enum_open(recp, &iter) != GPGME_No_Error) {
287                 gpgme_recipients_release(recp);
288                 return NULL;
289         }
290
291         encdata = g_string_sized_new(64);
292         while ((recipient = gpgme_recipients_enum_read(recp, &iter)) != NULL) {
293                 if (encdata->len > 0)
294                         g_string_append_c(encdata, ' ');
295                 g_string_append(encdata, recipient);
296         }
297
298         gpgme_recipients_release(recp);
299
300         data = encdata->str;
301         g_string_free(encdata, FALSE);
302
303         return data;
304 }
305
306 gboolean sgpgme_setup_signers(GpgmeCtx ctx, PrefsAccount *account)
307 {
308         GPGAccountConfig *config;
309
310         gpgme_signers_clear(ctx);
311
312         config = prefs_gpg_account_get_config(account);
313
314         if (config->sign_key != SIGN_KEY_DEFAULT) {
315                 gchar *keyid;
316                 GpgmeKey key;
317
318                 if (config->sign_key == SIGN_KEY_BY_FROM)
319                         keyid = account->address;
320                 else if (config->sign_key == SIGN_KEY_CUSTOM)
321                         keyid = config->sign_key_id;
322                 else
323                         return FALSE;
324
325                 gpgme_op_keylist_start(ctx, keyid, 1);
326                 while (!gpgme_op_keylist_next(ctx, &key)) {
327                         debug_print("adding key: %s\n", 
328                                 gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, NULL, 0));
329                         gpgme_signers_add(ctx, key);
330                         gpgme_key_release(key);
331                 }
332                 gpgme_op_keylist_end(ctx);
333         }
334
335         prefs_gpg_account_free_config(config);
336
337         return TRUE;
338 }
339
340 void sgpgme_init()
341 {
342         if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != 
343                         GPGME_No_Error) {  /* Also does some gpgme init */
344                 sgpgme_disable_all();
345                 debug_print("gpgme_engine_version:\n%s\n",
346                             gpgme_get_engine_info());
347
348                 if (prefs_gpg_get_config()->gpg_warning) {
349                         AlertValue val;
350
351                         val = alertpanel_message_with_disable
352                                 (_("Warning"),
353                                  _("GnuPG is not installed properly, or needs "
354                                    "to be upgraded.\n"
355                                    "OpenPGP support disabled."), ALERT_WARNING);
356                         if (val & G_ALERTDISABLE)
357                                 prefs_gpg_get_config()->gpg_warning = FALSE;
358                 }
359         }
360
361         gpgme_register_idle(idle_function_for_gpgme);
362 }
363
364 void sgpgme_done()
365 {
366         gpgmegtk_free_passphrase();
367         gpgme_register_idle(NULL);
368 }
369
370 #endif /* USE_GPGME */