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