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
privacy_set_error(const gchar * format,...)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
privacy_reset_error(void)44 void privacy_reset_error(void)
45 {
46 g_free(privacy_last_error);
47 privacy_last_error = NULL;
48 }
49
privacy_peek_error(void)50 gboolean privacy_peek_error(void)
51 {
52 return (privacy_last_error != NULL);
53 }
54
privacy_get_error(void)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
privacy_data_get_system(PrivacyData * data)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 */
privacy_register_system(PrivacySystem * system)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 */
privacy_unregister_system(PrivacySystem * system)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 */
privacy_free_privacydata(PrivacyData * privacydata)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 */
privacy_mimeinfo_is_signed(MimeInfo * mimeinfo)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
msginfo_set_signed_flag(GNode * node,gpointer data)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
privacy_msginfo_get_signed_state(MsgInfo * msginfo,gchar ** system)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 */
privacy_mimeinfo_check_signature(MimeInfo * mimeinfo)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
privacy_mimeinfo_get_sig_status(MimeInfo * mimeinfo)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
privacy_mimeinfo_sig_info_short(MimeInfo * mimeinfo)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
privacy_mimeinfo_sig_info_full(MimeInfo * mimeinfo)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
privacy_mimeinfo_is_encrypted(MimeInfo * mimeinfo)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
decrypt(MimeInfo * mimeinfo,PrivacySystem * system)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
privacy_mimeinfo_decrypt(MimeInfo * mimeinfo)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
privacy_get_system_ids()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
privacy_get_system(const gchar * id)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
privacy_system_get_name(const gchar * id)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
privacy_system_can_sign(const gchar * id)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
privacy_system_can_encrypt(const gchar * id)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
privacy_sign(const gchar * id,MimeInfo * target,PrefsAccount * account,const gchar * from_addr)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
privacy_get_encrypt_data(const gchar * id,GSList * recp_names)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
privacy_get_encrypt_warning(const gchar * id)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
privacy_inhibit_encrypt_warning(const gchar * id,gboolean inhibit)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
privacy_encrypt(const gchar * id,MimeInfo * mimeinfo,const gchar * encdata)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
privacy_auto_check_signatures(MimeInfo * mimeinfo)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 }
525