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