9e9fc865462d9f5f22897e1817b868667bc1b86e
[claws.git] / src / privacy.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 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 /**
151  * Check the signature of a MimeInfo. privacy_mimeinfo_is_signed
152  * should be called before otherwise it is done by this function.
153  * If the MimeInfo is not signed an error code will be returned.
154  *
155  * \return Error code indicating the result of the check,
156  *         < 0 if an error occured
157  */
158 gint privacy_mimeinfo_check_signature(MimeInfo *mimeinfo)
159 {
160         PrivacySystem *system;
161
162         g_return_val_if_fail(mimeinfo != NULL, -1);
163
164         if (mimeinfo->privacy == NULL)
165                 privacy_mimeinfo_is_signed(mimeinfo);
166         
167         if (mimeinfo->privacy == NULL)
168                 return -1;
169         
170         system = privacy_data_get_system(mimeinfo->privacy);
171         if (system == NULL)
172                 return -1;
173
174         if (system->check_signature == NULL)
175                 return -1;
176         
177         return system->check_signature(mimeinfo);
178 }
179
180 SignatureStatus privacy_mimeinfo_get_sig_status(MimeInfo *mimeinfo)
181 {
182         PrivacySystem *system;
183
184         g_return_val_if_fail(mimeinfo != NULL, -1);
185
186         if (mimeinfo->privacy == NULL)
187                 privacy_mimeinfo_is_signed(mimeinfo);
188         
189         if (mimeinfo->privacy == NULL)
190                 return SIGNATURE_UNCHECKED;
191         
192         system = privacy_data_get_system(mimeinfo->privacy);
193         if (system == NULL)
194                 return SIGNATURE_UNCHECKED;
195         if (system->get_sig_status == NULL)
196                 return SIGNATURE_UNCHECKED;
197         
198         return system->get_sig_status(mimeinfo);
199 }
200
201 gchar *privacy_mimeinfo_sig_info_short(MimeInfo *mimeinfo)
202 {
203         PrivacySystem *system;
204
205         g_return_val_if_fail(mimeinfo != NULL, NULL);
206
207         if (mimeinfo->privacy == NULL)
208                 privacy_mimeinfo_is_signed(mimeinfo);
209         
210         if (mimeinfo->privacy == NULL)
211                 return g_strdup(_("No signature found"));
212         
213         system = privacy_data_get_system(mimeinfo->privacy);
214         if (system == NULL)
215                 return g_strdup(_("No signature found"));
216         if (system->get_sig_info_short == NULL)
217                 return g_strdup(_("No information available"));
218         
219         return system->get_sig_info_short(mimeinfo);
220 }
221
222 gchar *privacy_mimeinfo_sig_info_full(MimeInfo *mimeinfo)
223 {
224         PrivacySystem *system;
225
226         g_return_val_if_fail(mimeinfo != NULL, NULL);
227
228         if (mimeinfo->privacy == NULL)
229                 privacy_mimeinfo_is_signed(mimeinfo);
230         
231         if (mimeinfo->privacy == NULL)
232                 return g_strdup(_("No signature found"));
233         
234         system = privacy_data_get_system(mimeinfo->privacy);
235         if (system == NULL)
236                 return g_strdup(_("No signature found"));
237         if (system->get_sig_info_full == NULL)
238                 return g_strdup(_("No information available"));
239         
240         return system->get_sig_info_full(mimeinfo);
241 }
242
243 gboolean privacy_mimeinfo_is_encrypted(MimeInfo *mimeinfo)
244 {
245         GSList *cur;
246         g_return_val_if_fail(mimeinfo != NULL, FALSE);
247
248         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
249                 PrivacySystem *system = (PrivacySystem *) cur->data;
250
251                 if(system->is_encrypted != NULL && system->is_encrypted(mimeinfo))
252                         return TRUE;
253         }
254
255         return FALSE;
256 }
257
258 static gint decrypt(MimeInfo *mimeinfo, PrivacySystem *system)
259 {
260         MimeInfo *decryptedinfo, *parentinfo;
261         gint childnumber;
262         
263         g_return_val_if_fail(system->decrypt != NULL, -1);
264         
265         decryptedinfo = system->decrypt(mimeinfo);
266         if (decryptedinfo == NULL)
267                 return -1;
268
269         parentinfo = procmime_mimeinfo_parent(mimeinfo);
270         childnumber = g_node_child_index(parentinfo->node, mimeinfo);
271         
272         procmime_mimeinfo_free_all(mimeinfo);
273
274         g_node_insert(parentinfo->node, childnumber, decryptedinfo->node);
275
276         return 0;
277 }
278
279 gint privacy_mimeinfo_decrypt(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 decrypt(mimeinfo, system);
289         }
290
291         return -1;
292 }
293
294 GSList *privacy_get_system_ids()
295 {
296         GSList *cur;
297         GSList *ret = NULL;
298
299         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
300                 PrivacySystem *system = (PrivacySystem *) cur->data;
301
302                 ret = g_slist_append(ret, g_strdup(system->id));
303         }
304
305         return ret;
306 }
307
308 static PrivacySystem *privacy_get_system(const gchar *id)
309 {
310         GSList *cur;
311
312         g_return_val_if_fail(id != NULL, NULL);
313
314         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
315                 PrivacySystem *system = (PrivacySystem *) cur->data;
316
317                 if(strcmp(id, system->id) == 0)
318                         return system;
319         }
320
321         return NULL;
322 }
323
324 const gchar *privacy_system_get_name(const gchar *id)
325 {
326         PrivacySystem *system;
327
328         g_return_val_if_fail(id != NULL, NULL);
329
330         system = privacy_get_system(id);
331         if (system == NULL)
332                 return NULL;
333
334         return system->name;
335 }
336
337 gboolean privacy_system_can_sign(const gchar *id)
338 {
339         PrivacySystem *system;
340
341         g_return_val_if_fail(id != NULL, FALSE);
342
343         system = privacy_get_system(id);
344         if (system == NULL)
345                 return FALSE;
346
347         return system->can_sign;
348 }
349
350 gboolean privacy_system_can_encrypt(const gchar *id)
351 {
352         PrivacySystem *system;
353
354         g_return_val_if_fail(id != NULL, FALSE);
355
356         system = privacy_get_system(id);
357         if (system == NULL)
358                 return FALSE;
359
360         return system->can_encrypt;
361 }
362
363 gboolean privacy_sign(const gchar *id, MimeInfo *target, PrefsAccount *account)
364 {
365         PrivacySystem *system;
366
367         g_return_val_if_fail(id != NULL, FALSE);
368         g_return_val_if_fail(target != NULL, FALSE);
369
370         system = privacy_get_system(id);
371         if (system == NULL)
372                 return FALSE;
373         if (!system->can_sign)
374                 return FALSE;
375         if (system->sign == NULL)
376                 return FALSE;
377
378         return system->sign(target, account);
379 }
380
381 gchar *privacy_get_encrypt_data(const gchar *id, GSList *recp_names)
382 {
383         PrivacySystem *system;
384
385         g_return_val_if_fail(id != NULL, NULL);
386         g_return_val_if_fail(recp_names != NULL, NULL);
387
388         system = privacy_get_system(id);
389         if (system == NULL)
390                 return NULL;
391         if (!system->can_encrypt)
392                 return NULL;
393         if (system->get_encrypt_data == NULL)
394                 return NULL;
395
396         return system->get_encrypt_data(recp_names);
397 }
398
399 const gchar *privacy_get_encrypt_warning(const gchar *id)
400 {
401         PrivacySystem *system;
402
403         g_return_val_if_fail(id != NULL, NULL);
404
405         system = privacy_get_system(id);
406         if (system == NULL)
407                 return NULL;
408         if (!system->can_encrypt)
409                 return NULL;
410         if (system->get_encrypt_warning == NULL)
411                 return NULL;
412
413         return system->get_encrypt_warning();
414 }
415
416 void privacy_inhibit_encrypt_warning(const gchar *id, gboolean inhibit)
417 {
418         PrivacySystem *system;
419
420         g_return_if_fail(id != NULL);
421
422         system = privacy_get_system(id);
423         if (system == NULL)
424                 return;
425         if (!system->can_encrypt)
426                 return;
427         if (system->inhibit_encrypt_warning == NULL)
428                 return;
429
430         system->inhibit_encrypt_warning(inhibit);
431 }
432
433 gboolean privacy_encrypt(const gchar *id, MimeInfo *mimeinfo, const gchar *encdata)
434 {
435         PrivacySystem *system;
436
437         g_return_val_if_fail(id != NULL, FALSE);
438         g_return_val_if_fail(mimeinfo != NULL, FALSE);
439         if (encdata == NULL) {
440                 privacy_set_error(_("No recipient keys defined."));
441                 return FALSE;
442         }
443
444         system = privacy_get_system(id);
445         if (system == NULL)
446                 return FALSE;
447         if (!system->can_encrypt)
448                 return FALSE;
449         if (system->encrypt == NULL)
450                 return FALSE;
451
452         return system->encrypt(mimeinfo, encdata);
453 }