3b9a14498ebd45886d6be69a75d29dc27fa4afb3
[claws.git] / src / privacy.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2009 Hiroyuki Yamamoto & the Claws Mail 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 3 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, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #include <glib.h>
21 #include <glib/gi18n.h>
22
23 #include "privacy.h"
24 #include "procmime.h"
25
26 static GSList *systems = NULL;
27 static gchar *privacy_last_error = NULL;
28
29 void privacy_set_error(const gchar *format, ...)
30 {
31         va_list args;
32         gchar buf[BUFSIZ];
33
34         va_start(args, format);
35         g_vsnprintf(buf, BUFSIZ, format, args);
36         va_end(args);
37         g_free(privacy_last_error);
38         privacy_last_error = g_strdup(buf);
39 }
40
41 static gchar tmp_privacy_error[BUFSIZ];
42
43 void privacy_reset_error(void)
44 {
45         g_free(privacy_last_error);
46         privacy_last_error = NULL;
47 }
48
49 gboolean privacy_peek_error(void)
50 {
51         return (privacy_last_error != NULL);
52 }
53
54 const gchar *privacy_get_error (void)
55 {
56         if (privacy_last_error) {
57                 strncpy2(tmp_privacy_error, privacy_last_error, BUFSIZ-1);
58                 privacy_reset_error();
59                 return tmp_privacy_error;
60         } else {
61                 return _("Unknown error");
62         }
63 }
64
65 static PrivacySystem *privacy_data_get_system(PrivacyData *data)
66 {
67         /* Make sure the cached system is still registered */
68         if (data->system && g_slist_find(systems, data->system))
69                 return data->system;
70         else
71                 return NULL;
72 }
73 /**
74  * Register a new Privacy System
75  *
76  * \param system The Privacy System that should be registered
77  */
78 void privacy_register_system(PrivacySystem *system)
79 {
80         systems = g_slist_append(systems, system);
81 }
82
83 /**
84  * Unregister a new Privacy System. The system must not be in
85  * use anymore when it is unregistered.
86  *
87  * \param system The Privacy System that should be unregistered
88  */
89 void privacy_unregister_system(PrivacySystem *system)
90 {
91         systems = g_slist_remove(systems, system);
92 }
93
94 /**
95  * Free a PrivacyData of a PrivacySystem
96  *
97  * \param privacydata The data to free
98  */
99 void privacy_free_privacydata(PrivacyData *privacydata)
100 {
101         PrivacySystem *system = NULL;
102         
103         g_return_if_fail(privacydata != NULL);
104
105         system = privacy_data_get_system(privacydata);
106         if (!system)
107                 return;
108         system->free_privacydata(privacydata);
109 }
110
111 /**
112  * Check if a MimeInfo is signed with one of the available
113  * privacy system. If a privacydata is set in the MimeInfo
114  * it will directory return the return value by the system
115  * set in the privacy data or check all available privacy
116  * systems otherwise.
117  *
118  * \return True if the MimeInfo has a signature
119  */
120 gboolean privacy_mimeinfo_is_signed(MimeInfo *mimeinfo)
121 {
122         GSList *cur;
123         g_return_val_if_fail(mimeinfo != NULL, FALSE);
124
125         if (mimeinfo->privacy != NULL) {
126                 PrivacySystem *system = 
127                         privacy_data_get_system(mimeinfo->privacy);
128
129                 if (system == NULL) {
130                         mimeinfo->privacy = NULL;
131                         goto try_others;
132                 }
133
134                 if (system->is_signed != NULL)
135                         return system->is_signed(mimeinfo);
136                 else
137                         return FALSE;
138         }
139 try_others:
140         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
141                 PrivacySystem *system = (PrivacySystem *) cur->data;
142
143                 if(system->is_signed != NULL && system->is_signed(mimeinfo))
144                         return TRUE;
145         }
146
147         return FALSE;
148 }
149
150 struct SignedState {
151         MsgInfo *msginfo;
152         gchar **system;
153 };
154
155 static void msginfo_set_signed_flag(GNode *node, gpointer data)
156 {
157         struct SignedState *sstate = (struct SignedState *)data;
158         MsgInfo *msginfo = sstate->msginfo;
159         MimeInfo *mimeinfo = node->data;
160         
161         if (privacy_mimeinfo_is_signed(mimeinfo)) {
162                 procmsg_msginfo_set_flags(msginfo, 0, MSG_SIGNED);
163                 if (sstate->system && !*(sstate->system) && mimeinfo->privacy)
164                         *(sstate->system) = g_strdup(mimeinfo->privacy->system->id);
165         }
166         if (privacy_mimeinfo_is_encrypted(mimeinfo)) {
167                 procmsg_msginfo_set_flags(msginfo, 0, MSG_ENCRYPTED);
168                 if (sstate->system && !*(sstate->system) && mimeinfo->privacy)
169                         *(sstate->system) = g_strdup(mimeinfo->privacy->system->id);
170         } else {
171                 /* searching inside encrypted parts doesn't really make sense */
172                 g_node_children_foreach(mimeinfo->node, G_TRAVERSE_ALL, msginfo_set_signed_flag, sstate);
173         }
174 }
175
176 void privacy_msginfo_get_signed_state(MsgInfo *msginfo, gchar **system)
177 {
178         struct SignedState sstate;
179         MimeInfo *mimeinfo = procmime_scan_message(msginfo);
180
181         sstate.msginfo = msginfo;
182         sstate.system = system;
183         g_node_children_foreach(mimeinfo->node, G_TRAVERSE_ALL, msginfo_set_signed_flag, &sstate);
184 }
185
186 /**
187  * Check the signature of a MimeInfo. privacy_mimeinfo_is_signed
188  * should be called before otherwise it is done by this function.
189  * If the MimeInfo is not signed an error code will be returned.
190  *
191  * \return Error code indicating the result of the check,
192  *         < 0 if an error occured
193  */
194 gint privacy_mimeinfo_check_signature(MimeInfo *mimeinfo)
195 {
196         PrivacySystem *system;
197
198         g_return_val_if_fail(mimeinfo != NULL, -1);
199
200         if (mimeinfo->privacy == NULL)
201                 privacy_mimeinfo_is_signed(mimeinfo);
202         
203         if (mimeinfo->privacy == NULL)
204                 return -1;
205         
206         system = privacy_data_get_system(mimeinfo->privacy);
207         if (system == NULL)
208                 return -1;
209
210         if (system->check_signature == NULL)
211                 return -1;
212         
213         return system->check_signature(mimeinfo);
214 }
215
216 SignatureStatus privacy_mimeinfo_get_sig_status(MimeInfo *mimeinfo)
217 {
218         PrivacySystem *system;
219
220         g_return_val_if_fail(mimeinfo != NULL, -1);
221
222         if (mimeinfo->privacy == NULL)
223                 privacy_mimeinfo_is_signed(mimeinfo);
224         
225         if (mimeinfo->privacy == NULL)
226                 return SIGNATURE_UNCHECKED;
227         
228         system = privacy_data_get_system(mimeinfo->privacy);
229         if (system == NULL)
230                 return SIGNATURE_UNCHECKED;
231         if (system->get_sig_status == NULL)
232                 return SIGNATURE_UNCHECKED;
233         
234         return system->get_sig_status(mimeinfo);
235 }
236
237 gchar *privacy_mimeinfo_sig_info_short(MimeInfo *mimeinfo)
238 {
239         PrivacySystem *system;
240
241         g_return_val_if_fail(mimeinfo != NULL, NULL);
242
243         if (mimeinfo->privacy == NULL)
244                 privacy_mimeinfo_is_signed(mimeinfo);
245         
246         if (mimeinfo->privacy == NULL)
247                 return g_strdup(_("No signature found"));
248         
249         system = privacy_data_get_system(mimeinfo->privacy);
250         if (system == NULL)
251                 return g_strdup(_("No signature found"));
252         if (system->get_sig_info_short == NULL)
253                 return g_strdup(_("No information available"));
254         
255         return system->get_sig_info_short(mimeinfo);
256 }
257
258 gchar *privacy_mimeinfo_sig_info_full(MimeInfo *mimeinfo)
259 {
260         PrivacySystem *system;
261
262         g_return_val_if_fail(mimeinfo != NULL, NULL);
263
264         if (mimeinfo->privacy == NULL)
265                 privacy_mimeinfo_is_signed(mimeinfo);
266         
267         if (mimeinfo->privacy == NULL)
268                 return g_strdup(_("No signature found"));
269         
270         system = privacy_data_get_system(mimeinfo->privacy);
271         if (system == NULL)
272                 return g_strdup(_("No signature found"));
273         if (system->get_sig_info_full == NULL)
274                 return g_strdup(_("No information available"));
275         
276         return system->get_sig_info_full(mimeinfo);
277 }
278
279 gboolean privacy_mimeinfo_is_encrypted(MimeInfo *mimeinfo)
280 {
281         GSList *cur;
282         g_return_val_if_fail(mimeinfo != NULL, FALSE);
283
284         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
285                 PrivacySystem *system = (PrivacySystem *) cur->data;
286
287                 if(system->is_encrypted != NULL && system->is_encrypted(mimeinfo))
288                         return TRUE;
289         }
290
291         return FALSE;
292 }
293
294 static gint decrypt(MimeInfo *mimeinfo, PrivacySystem *system)
295 {
296         MimeInfo *decryptedinfo, *parentinfo;
297         gint childnumber;
298         
299         g_return_val_if_fail(system->decrypt != NULL, -1);
300         
301         decryptedinfo = system->decrypt(mimeinfo);
302         if (decryptedinfo == NULL)
303                 return -1;
304
305         parentinfo = procmime_mimeinfo_parent(mimeinfo);
306         childnumber = g_node_child_index(parentinfo->node, mimeinfo);
307         
308         procmime_mimeinfo_free_all(mimeinfo);
309
310         g_node_insert(parentinfo->node, childnumber, decryptedinfo->node);
311
312         return 0;
313 }
314
315 gint privacy_mimeinfo_decrypt(MimeInfo *mimeinfo)
316 {
317         GSList *cur;
318         g_return_val_if_fail(mimeinfo != NULL, FALSE);
319
320         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
321                 PrivacySystem *system = (PrivacySystem *) cur->data;
322
323                 if(system->is_encrypted != NULL && system->is_encrypted(mimeinfo))
324                         return decrypt(mimeinfo, system);
325         }
326
327         return -1;
328 }
329
330 GSList *privacy_get_system_ids()
331 {
332         GSList *cur;
333         GSList *ret = NULL;
334
335         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
336                 PrivacySystem *system = (PrivacySystem *) cur->data;
337
338                 ret = g_slist_append(ret, g_strdup(system->id));
339         }
340
341         return ret;
342 }
343
344 static PrivacySystem *privacy_get_system(const gchar *id)
345 {
346         GSList *cur;
347
348         g_return_val_if_fail(id != NULL, NULL);
349
350         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
351                 PrivacySystem *system = (PrivacySystem *) cur->data;
352
353                 if(strcmp(id, system->id) == 0)
354                         return system;
355         }
356
357         return NULL;
358 }
359
360 const gchar *privacy_system_get_name(const gchar *id)
361 {
362         PrivacySystem *system;
363
364         g_return_val_if_fail(id != NULL, NULL);
365
366         system = privacy_get_system(id);
367         if (system == NULL)
368                 return NULL;
369
370         return system->name;
371 }
372
373 gboolean privacy_system_can_sign(const gchar *id)
374 {
375         PrivacySystem *system;
376
377         g_return_val_if_fail(id != NULL, FALSE);
378
379         system = privacy_get_system(id);
380         if (system == NULL)
381                 return FALSE;
382
383         return system->can_sign;
384 }
385
386 gboolean privacy_system_can_encrypt(const gchar *id)
387 {
388         PrivacySystem *system;
389
390         g_return_val_if_fail(id != NULL, FALSE);
391
392         system = privacy_get_system(id);
393         if (system == NULL)
394                 return FALSE;
395
396         return system->can_encrypt;
397 }
398
399 gboolean privacy_sign(const gchar *id, MimeInfo *target, PrefsAccount *account, const gchar *from_addr)
400 {
401         PrivacySystem *system;
402
403         g_return_val_if_fail(id != NULL, FALSE);
404         g_return_val_if_fail(target != NULL, FALSE);
405
406         system = privacy_get_system(id);
407         if (system == NULL)
408                 return FALSE;
409         if (!system->can_sign)
410                 return FALSE;
411         if (system->sign == NULL)
412                 return FALSE;
413
414         return system->sign(target, account, from_addr);
415 }
416
417 gchar *privacy_get_encrypt_data(const gchar *id, GSList *recp_names)
418 {
419         PrivacySystem *system;
420
421         g_return_val_if_fail(id != NULL, NULL);
422         g_return_val_if_fail(recp_names != NULL, NULL);
423
424         system = privacy_get_system(id);
425         if (system == NULL)
426                 return NULL;
427         if (!system->can_encrypt)
428                 return NULL;
429         if (system->get_encrypt_data == NULL)
430                 return NULL;
431
432         return system->get_encrypt_data(recp_names);
433 }
434
435 const gchar *privacy_get_encrypt_warning(const gchar *id)
436 {
437         PrivacySystem *system;
438
439         g_return_val_if_fail(id != NULL, NULL);
440
441         system = privacy_get_system(id);
442         if (system == NULL)
443                 return NULL;
444         if (!system->can_encrypt)
445                 return NULL;
446         if (system->get_encrypt_warning == NULL)
447                 return NULL;
448
449         return system->get_encrypt_warning();
450 }
451
452 void privacy_inhibit_encrypt_warning(const gchar *id, gboolean inhibit)
453 {
454         PrivacySystem *system;
455
456         g_return_if_fail(id != NULL);
457
458         system = privacy_get_system(id);
459         if (system == NULL)
460                 return;
461         if (!system->can_encrypt)
462                 return;
463         if (system->inhibit_encrypt_warning == NULL)
464                 return;
465
466         system->inhibit_encrypt_warning(inhibit);
467 }
468
469 gboolean privacy_encrypt(const gchar *id, MimeInfo *mimeinfo, const gchar *encdata)
470 {
471         PrivacySystem *system;
472
473         g_return_val_if_fail(id != NULL, FALSE);
474         g_return_val_if_fail(mimeinfo != NULL, FALSE);
475         if (encdata == NULL) {
476                 privacy_set_error(_("No recipient keys defined."));
477                 return FALSE;
478         }
479
480         system = privacy_get_system(id);
481         if (system == NULL)
482                 return FALSE;
483         if (!system->can_encrypt)
484                 return FALSE;
485         if (system->encrypt == NULL)
486                 return FALSE;
487
488         return system->encrypt(mimeinfo, encdata);
489 }