2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
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.
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.
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/>.
23 #include <glib/gi18n.h>
29 static GSList
*systems
= NULL
;
30 static gchar
*privacy_last_error
= NULL
;
32 void privacy_set_error(const gchar
*format
, ...)
37 va_start(args
, format
);
38 g_vsnprintf(buf
, BUFSIZ
, format
, args
);
40 g_free(privacy_last_error
);
41 privacy_last_error
= g_strdup(buf
);
44 static gchar tmp_privacy_error
[BUFSIZ
];
46 void privacy_reset_error(void)
48 g_free(privacy_last_error
);
49 privacy_last_error
= NULL
;
52 gboolean
privacy_peek_error(void)
54 return (privacy_last_error
!= NULL
);
57 const gchar
*privacy_get_error (void)
59 if (privacy_last_error
) {
60 strncpy2(tmp_privacy_error
, privacy_last_error
, BUFSIZ
-1);
61 privacy_reset_error();
62 return tmp_privacy_error
;
64 return _("Unknown error");
68 static PrivacySystem
*privacy_data_get_system(PrivacyData
*data
)
70 /* Make sure the cached system is still registered */
71 if (data
->system
&& g_slist_find(systems
, data
->system
))
77 * Register a new Privacy System
79 * \param system The Privacy System that should be registered
81 void privacy_register_system(PrivacySystem
*system
)
83 systems
= g_slist_append(systems
, system
);
87 * Unregister a new Privacy System. The system must not be in
88 * use anymore when it is unregistered.
90 * \param system The Privacy System that should be unregistered
92 void privacy_unregister_system(PrivacySystem
*system
)
94 systems
= g_slist_remove(systems
, system
);
98 * Free a PrivacyData of a PrivacySystem
100 * \param privacydata The data to free
102 void privacy_free_privacydata(PrivacyData
*privacydata
)
104 PrivacySystem
*system
= NULL
;
106 cm_return_if_fail(privacydata
!= NULL
);
108 system
= privacy_data_get_system(privacydata
);
111 system
->free_privacydata(privacydata
);
114 void privacy_free_signature_data(SignatureData
*sig_data
)
116 cm_return_if_fail(sig_data
!= NULL
);
118 g_free(sig_data
->info_short
);
119 g_free(sig_data
->info_full
);
123 void privacy_free_sig_check_task_result(gpointer data
)
125 SigCheckTaskResult
*result
= (SigCheckTaskResult
*)data
;
127 privacy_free_signature_data(result
->sig_data
);
129 procmime_mimeinfo_free_all(&result
->newinfo
);
134 * Check if a MimeInfo is signed with one of the available
135 * privacy system. If a privacydata is set in the MimeInfo
136 * it will directory return the return value by the system
137 * set in the privacy data or check all available privacy
140 * \return True if the MimeInfo has a signature
142 gboolean
privacy_mimeinfo_is_signed(MimeInfo
*mimeinfo
)
145 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
147 if (mimeinfo
->privacy
!= NULL
) {
148 PrivacySystem
*system
=
149 privacy_data_get_system(mimeinfo
->privacy
);
151 if (system
== NULL
) {
152 mimeinfo
->privacy
= NULL
;
156 if (system
->is_signed
!= NULL
)
157 return system
->is_signed(mimeinfo
);
162 for(cur
= systems
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
163 PrivacySystem
*system
= (PrivacySystem
*) cur
->data
;
165 if(system
->is_signed
!= NULL
&& system
->is_signed(mimeinfo
))
177 static void msginfo_set_signed_flag(GNode
*node
, gpointer data
)
179 struct SignedState
*sstate
= (struct SignedState
*)data
;
180 MsgInfo
*msginfo
= sstate
->msginfo
;
181 MimeInfo
*mimeinfo
= node
->data
;
183 if (privacy_mimeinfo_is_signed(mimeinfo
)) {
184 procmsg_msginfo_set_flags(msginfo
, 0, MSG_SIGNED
);
185 if (sstate
->system
&& !*(sstate
->system
) && mimeinfo
->privacy
)
186 *(sstate
->system
) = g_strdup(mimeinfo
->privacy
->system
->id
);
188 if (privacy_mimeinfo_is_encrypted(mimeinfo
)) {
189 procmsg_msginfo_set_flags(msginfo
, 0, MSG_ENCRYPTED
);
190 if (sstate
->system
&& !*(sstate
->system
) && mimeinfo
->privacy
)
191 *(sstate
->system
) = g_strdup(mimeinfo
->privacy
->system
->id
);
193 /* searching inside encrypted parts doesn't really make sense */
194 g_node_children_foreach(mimeinfo
->node
, G_TRAVERSE_ALL
, msginfo_set_signed_flag
, sstate
);
198 void privacy_msginfo_get_signed_state(MsgInfo
*msginfo
, gchar
**system
)
200 struct SignedState sstate
;
201 MimeInfo
*mimeinfo
= procmime_scan_message(msginfo
);
204 sstate
.msginfo
= msginfo
;
205 sstate
.system
= system
;
206 g_node_children_foreach(mimeinfo
->node
, G_TRAVERSE_ALL
, msginfo_set_signed_flag
, &sstate
);
210 * Check the signature of a MimeInfo. privacy_mimeinfo_is_signed
211 * should be called before otherwise it is done by this function.
212 * If the MimeInfo is not signed an error code will be returned.
214 * \return Error code indicating the result of the check,
215 * < 0 if an error occurred
217 gint
privacy_mimeinfo_check_signature(MimeInfo
*mimeinfo
,
218 GCancellable
*cancellable
,
219 GAsyncReadyCallback callback
,
222 PrivacySystem
*system
;
224 if (mimeinfo
== NULL
)
225 g_error("siginfo was NULL");
227 if (mimeinfo
->privacy
== NULL
) {
228 g_warning("mimeinfo->privacy was NULL");
230 privacy_mimeinfo_is_signed(mimeinfo
);
231 if (mimeinfo
->privacy
== NULL
) {
232 g_error("failed to set up PrivacyData");
236 system
= privacy_data_get_system(mimeinfo
->privacy
);
238 g_error("failed to get privacy system");
239 else if (system
->check_signature
== NULL
)
240 g_error("didn't find check_signature function");
242 return system
->check_signature(mimeinfo
, cancellable
, callback
, user_data
);
245 SignatureStatus
privacy_mimeinfo_get_sig_status(MimeInfo
*mimeinfo
)
247 PrivacySystem
*system
;
249 cm_return_val_if_fail(mimeinfo
!= NULL
, -1);
251 if (mimeinfo
->privacy
== NULL
) {
252 privacy_mimeinfo_is_signed(mimeinfo
);
254 if (mimeinfo
->privacy
== NULL
)
255 return SIGNATURE_UNCHECKED
;
258 system
= privacy_data_get_system(mimeinfo
->privacy
);
260 return SIGNATURE_UNCHECKED
;
262 if (mimeinfo
->sig_data
== NULL
)
263 return SIGNATURE_UNCHECKED
;
265 return mimeinfo
->sig_data
->status
;
268 gchar
*privacy_mimeinfo_get_sig_info(MimeInfo
*mimeinfo
, gboolean full
)
270 PrivacySystem
*system
;
273 cm_return_val_if_fail(mimeinfo
!= NULL
, NULL
);
275 if (mimeinfo
->privacy
== NULL
) {
276 privacy_mimeinfo_is_signed(mimeinfo
);
278 if (mimeinfo
->privacy
== NULL
)
279 return _("No signature found");
282 system
= privacy_data_get_system(mimeinfo
->privacy
);
284 return _("No signature found");
286 if (mimeinfo
->sig_data
== NULL
)
287 return _("No information available");
289 info
= full
? mimeinfo
->sig_data
->info_full
: mimeinfo
->sig_data
->info_short
;
291 return _("No information available");
296 gboolean
privacy_mimeinfo_is_encrypted(MimeInfo
*mimeinfo
)
299 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
301 for(cur
= systems
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
302 PrivacySystem
*system
= (PrivacySystem
*) cur
->data
;
304 if(system
->is_encrypted
!= NULL
&& system
->is_encrypted(mimeinfo
))
311 static gint
decrypt(MimeInfo
*mimeinfo
, PrivacySystem
*system
)
313 MimeInfo
*decryptedinfo
, *parentinfo
;
316 cm_return_val_if_fail(system
->decrypt
!= NULL
, -1);
318 decryptedinfo
= system
->decrypt(mimeinfo
);
319 if (decryptedinfo
== NULL
)
322 parentinfo
= procmime_mimeinfo_parent(mimeinfo
);
323 childnumber
= g_node_child_index(parentinfo
->node
, mimeinfo
);
325 procmime_mimeinfo_free_all(&mimeinfo
);
327 g_node_insert(parentinfo
->node
, childnumber
, decryptedinfo
->node
);
332 gint
privacy_mimeinfo_decrypt(MimeInfo
*mimeinfo
)
335 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
337 procmime_decode_content(mimeinfo
);
339 for(cur
= systems
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
340 PrivacySystem
*system
= (PrivacySystem
*) cur
->data
;
342 if(system
->is_encrypted
!= NULL
&& system
->is_encrypted(mimeinfo
))
343 return decrypt(mimeinfo
, system
);
349 GSList
*privacy_get_system_ids()
354 for(cur
= systems
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
355 PrivacySystem
*system
= (PrivacySystem
*) cur
->data
;
357 ret
= g_slist_append(ret
, g_strdup(system
->id
));
363 static PrivacySystem
*privacy_get_system(const gchar
*id
)
367 cm_return_val_if_fail(id
!= NULL
, NULL
);
369 for(cur
= systems
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
370 PrivacySystem
*system
= (PrivacySystem
*) cur
->data
;
372 if(strcmp(id
, system
->id
) == 0)
379 const gchar
*privacy_system_get_name(const gchar
*id
)
381 PrivacySystem
*system
;
383 cm_return_val_if_fail(id
!= NULL
, NULL
);
385 system
= privacy_get_system(id
);
392 gboolean
privacy_system_can_sign(const gchar
*id
)
394 PrivacySystem
*system
;
396 cm_return_val_if_fail(id
!= NULL
, FALSE
);
398 system
= privacy_get_system(id
);
402 return system
->can_sign
;
405 gboolean
privacy_system_can_encrypt(const gchar
*id
)
407 PrivacySystem
*system
;
409 cm_return_val_if_fail(id
!= NULL
, FALSE
);
411 system
= privacy_get_system(id
);
415 return system
->can_encrypt
;
418 gboolean
privacy_sign(const gchar
*id
, MimeInfo
*target
, PrefsAccount
*account
, const gchar
*from_addr
)
420 PrivacySystem
*system
;
422 cm_return_val_if_fail(id
!= NULL
, FALSE
);
423 cm_return_val_if_fail(target
!= NULL
, FALSE
);
425 system
= privacy_get_system(id
);
428 if (!system
->can_sign
)
430 if (system
->sign
== NULL
)
433 return system
->sign(target
, account
, from_addr
);
436 gchar
*privacy_get_encrypt_data(const gchar
*id
, GSList
*recp_names
)
438 PrivacySystem
*system
;
440 GSList
*uniq_names
= NULL
, *cur
;
442 cm_return_val_if_fail(id
!= NULL
, NULL
);
443 cm_return_val_if_fail(recp_names
!= NULL
, NULL
);
445 system
= privacy_get_system(id
);
448 if (!system
->can_encrypt
)
450 if (system
->get_encrypt_data
== NULL
)
453 for (cur
= recp_names
; cur
; cur
= cur
->next
) {
454 if (!g_slist_find_custom(uniq_names
, cur
->data
, (GCompareFunc
)strcmp
)) {
455 uniq_names
= g_slist_prepend(uniq_names
, cur
->data
);
458 ret
= system
->get_encrypt_data(uniq_names
);
460 g_slist_free(uniq_names
);
464 const gchar
*privacy_get_encrypt_warning(const gchar
*id
)
466 PrivacySystem
*system
;
468 cm_return_val_if_fail(id
!= NULL
, NULL
);
470 system
= privacy_get_system(id
);
473 if (!system
->can_encrypt
)
475 if (system
->get_encrypt_warning
== NULL
)
478 return system
->get_encrypt_warning();
481 void privacy_inhibit_encrypt_warning(const gchar
*id
, gboolean inhibit
)
483 PrivacySystem
*system
;
485 cm_return_if_fail(id
!= NULL
);
487 system
= privacy_get_system(id
);
490 if (!system
->can_encrypt
)
492 if (system
->inhibit_encrypt_warning
== NULL
)
495 system
->inhibit_encrypt_warning(inhibit
);
498 gboolean
privacy_encrypt(const gchar
*id
, MimeInfo
*mimeinfo
, const gchar
*encdata
)
500 PrivacySystem
*system
;
502 cm_return_val_if_fail(id
!= NULL
, FALSE
);
503 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
504 if (encdata
== NULL
) {
505 privacy_set_error(_("No recipient keys defined."));
509 system
= privacy_get_system(id
);
512 if (!system
->can_encrypt
)
514 if (system
->encrypt
== NULL
)
517 return system
->encrypt(mimeinfo
, encdata
);
520 gboolean
privacy_auto_check_signatures(MimeInfo
*mimeinfo
)
522 PrivacySystem
*system
;
524 cm_return_val_if_fail(mimeinfo
!= NULL
, FALSE
);
526 if (mimeinfo
->privacy
== NULL
)
527 privacy_mimeinfo_is_signed(mimeinfo
);
529 if (mimeinfo
->privacy
== NULL
)
532 system
= privacy_data_get_system(mimeinfo
->privacy
);
535 if (system
->auto_check_signatures
== NULL
)
538 return system
->auto_check_signatures();