Migrate certificates, icons, logs to XDG dirs
[pidgin-git.git] / libpurple / keyring.c
blobad200b2f83059fa117deb9122116420aaa692586
1 /* purple
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program ; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include <glib.h>
23 #include <string.h>
24 #include "account.h"
25 #include "keyring.h"
26 #include "signals.h"
27 #include "core.h"
28 #include "debug.h"
29 #include "internal.h"
30 #include "dbus-maybe.h"
31 #include "plugins.h"
33 struct _PurpleKeyring
35 gchar *name;
36 gchar *id;
37 PurpleKeyringRead read_password;
38 PurpleKeyringSave save_password;
39 PurpleKeyringCancelRequests cancel_requests;
40 PurpleKeyringClose close_keyring;
41 PurpleKeyringImportPassword import_password;
42 PurpleKeyringExportPassword export_password;
43 PurpleKeyringReadSettings read_settings;
44 PurpleKeyringApplySettings apply_settings;
46 gboolean is_closing;
47 gboolean is_cancelling;
48 gboolean close_after_cancel;
51 typedef struct
53 GError *error;
54 PurpleKeyringSetInUseCallback cb;
55 gpointer cb_data;
56 PurpleKeyring *new_kr;
57 PurpleKeyring *old_kr;
60 * We are done when finished is positive and read_outstanding is zero.
62 gboolean finished;
63 int read_outstanding;
65 gboolean abort;
66 gboolean force;
67 gboolean succeeded;
68 } PurpleKeyringChangeTracker;
70 typedef void (*PurpleKeyringDropCallback)(gpointer data);
72 typedef struct
74 PurpleKeyringDropCallback cb;
75 gpointer cb_data;
77 gboolean finished;
78 int drop_outstanding;
79 } PurpleKeyringDropTracker;
81 typedef struct
83 PurpleKeyringSaveCallback cb;
84 gpointer cb_data;
85 } PurpleKeyringSetPasswordData;
87 typedef struct
89 gchar *keyring_id;
90 gchar *mode;
91 gchar *data;
92 } PurpleKeyringFailedImport;
94 static void
95 purple_keyring_change_tracker_free(PurpleKeyringChangeTracker *tracker)
97 if (tracker->error)
98 g_error_free(tracker->error);
99 g_free(tracker);
102 static void
103 purple_keyring_failed_import_free(PurpleKeyringFailedImport *import)
105 g_return_if_fail(import != NULL);
107 g_free(import->keyring_id);
108 g_free(import->mode);
109 purple_str_wipe(import->data);
110 g_free(import);
113 static void
114 purple_keyring_close(PurpleKeyring *keyring);
116 static void
117 purple_keyring_drop_passwords(PurpleKeyring *keyring,
118 PurpleKeyringDropCallback cb, gpointer data);
120 /* A list of available keyrings */
121 static GList *purple_keyring_keyrings = NULL;
123 /* Keyring being used. */
124 static PurpleKeyring *purple_keyring_inuse = NULL;
126 /* Keyring id marked to use (may not be loadable). */
127 static gchar *purple_keyring_to_use = NULL;
129 static guint purple_keyring_pref_cbid = 0;
130 static GList *purple_keyring_loaded_plugins = NULL;
131 static PurpleKeyringChangeTracker *current_change_tracker = NULL;
132 static gboolean purple_keyring_is_quitting = FALSE;
133 static GHashTable *purple_keyring_failed_imports = NULL;
135 static const gchar *
136 purple_keyring_print_account(PurpleAccount *account)
138 static gchar print_buff[100];
140 if (account == NULL) {
141 g_snprintf(print_buff, 100, "(null)");
142 return print_buff;
145 g_snprintf(print_buff, 100, "%s:%s",
146 purple_account_get_protocol_id(account),
147 purple_account_get_username(account));
148 return print_buff;
151 /**************************************************************************/
152 /* Setting used keyrings */
153 /**************************************************************************/
155 PurpleKeyring *
156 purple_keyring_find_keyring_by_id(const gchar *id)
158 GList *it;
160 for (it = purple_keyring_keyrings; it != NULL; it = it->next) {
161 PurpleKeyring *keyring = it->data;
162 const gchar *curr_id = purple_keyring_get_id(keyring);
164 if (g_strcmp0(id, curr_id) == 0)
165 return keyring;
168 return NULL;
171 static void
172 purple_keyring_pref_callback(const gchar *pref, PurplePrefType type,
173 gconstpointer id, gpointer data)
175 PurpleKeyring *new_keyring;
177 g_return_if_fail(g_strcmp0(pref, "/purple/keyring/active") == 0);
178 g_return_if_fail(type == PURPLE_PREF_STRING);
179 g_return_if_fail(id != NULL);
181 new_keyring = purple_keyring_find_keyring_by_id(id);
182 g_return_if_fail(new_keyring != NULL);
184 purple_keyring_set_inuse(new_keyring, FALSE, NULL, NULL);
187 static void
188 purple_keyring_pref_connect(void)
190 g_return_if_fail(purple_keyring_pref_cbid == 0);
192 purple_keyring_pref_cbid = purple_prefs_connect_callback(NULL,
193 "/purple/keyring/active", purple_keyring_pref_callback, NULL);
196 static void
197 purple_keyring_pref_disconnect(void)
199 g_return_if_fail(purple_keyring_pref_cbid != 0);
201 purple_prefs_disconnect_callback(purple_keyring_pref_cbid);
202 purple_keyring_pref_cbid = 0;
205 PurpleKeyring *
206 purple_keyring_get_inuse(void)
208 return purple_keyring_inuse;
211 static void
212 purple_keyring_set_inuse_drop_cb(gpointer _tracker)
214 PurpleKeyringChangeTracker *tracker = _tracker;
216 g_return_if_fail(tracker != NULL);
218 if (tracker->succeeded) {
219 purple_keyring_close(tracker->old_kr);
221 purple_debug_info("keyring", "Successfully changed keyring.\n");
223 purple_keyring_inuse = tracker->new_kr;
224 current_change_tracker = NULL;
226 if (tracker->cb != NULL)
227 tracker->cb(NULL, tracker->cb_data);
228 purple_keyring_change_tracker_free(tracker);
229 return;
232 purple_debug_error("keyring", "Failed to change keyring, aborting.\n");
234 purple_keyring_close(tracker->new_kr);
236 purple_keyring_pref_disconnect();
237 purple_prefs_set_string("/purple/keyring/active",
238 purple_keyring_get_id(tracker->old_kr));
239 purple_keyring_pref_connect();
241 current_change_tracker = NULL;
243 if (tracker->error == NULL) {
244 tracker->error = g_error_new(PURPLE_KEYRING_ERROR,
245 PURPLE_KEYRING_ERROR_UNKNOWN,
246 _("An unknown error has occured."));
249 if (tracker->cb != NULL)
250 tracker->cb(tracker->error, tracker->cb_data);
252 purple_keyring_change_tracker_free(tracker);
255 static void
256 purple_keyring_set_inuse_save_cb(PurpleAccount *account, GError *error,
257 gpointer _tracker)
259 PurpleKeyringChangeTracker *tracker = _tracker;
261 g_return_if_fail(account != NULL);
262 g_return_if_fail(tracker != NULL);
264 tracker->read_outstanding--;
266 if (error == NULL) {
267 /* no error */
268 } else if (g_error_matches(error, PURPLE_KEYRING_ERROR,
269 PURPLE_KEYRING_ERROR_NOPASSWORD))
271 if (purple_debug_is_verbose()) {
272 purple_debug_misc("keyring", "No password found while "
273 "changing keyring for account %s: %s.\n",
274 purple_keyring_print_account(account),
275 error->message);
277 } else if (g_error_matches(error, PURPLE_KEYRING_ERROR,
278 PURPLE_KEYRING_ERROR_ACCESSDENIED))
280 purple_debug_info("keyring", "Access denied while changing "
281 "keyring for account %s: %s.\n",
282 purple_keyring_print_account(account), error->message);
283 tracker->abort = TRUE;
284 if (tracker->error != NULL)
285 g_error_free(tracker->error);
286 tracker->error = g_error_copy(error);
287 } else if (g_error_matches(error, PURPLE_KEYRING_ERROR,
288 PURPLE_KEYRING_ERROR_CANCELLED))
290 purple_debug_info("keyring", "Operation cancelled while "
291 "changing keyring for account %s: %s.\n",
292 purple_keyring_print_account(account), error->message);
293 tracker->abort = TRUE;
294 if (tracker->error == NULL)
295 tracker->error = g_error_copy(error);
296 } else if (g_error_matches(error, PURPLE_KEYRING_ERROR,
297 PURPLE_KEYRING_ERROR_BACKENDFAIL))
299 purple_debug_error("keyring", "Failed to communicate with "
300 "backend while changing keyring for account %s: %s. "
301 "Aborting changes.\n",
302 purple_keyring_print_account(account), error->message);
303 tracker->abort = TRUE;
304 if (tracker->error != NULL)
305 g_error_free(tracker->error);
306 tracker->error = g_error_copy(error);
307 } else {
308 purple_debug_error("keyring", "Unknown error while changing "
309 "keyring for account %s: %s. Aborting changes.\n",
310 purple_keyring_print_account(account), error->message);
311 tracker->abort = TRUE;
312 if (tracker->error == NULL)
313 tracker->error = g_error_copy(error);
316 purple_signal_emit(purple_keyring_get_handle(), "password-migration",
317 account);
319 if (!tracker->finished || tracker->read_outstanding > 0)
320 return;
322 /* This was the last one. */
323 if (tracker->abort && !tracker->force) {
324 tracker->succeeded = FALSE;
325 purple_keyring_drop_passwords(tracker->new_kr,
326 purple_keyring_set_inuse_drop_cb, tracker);
327 } else {
328 tracker->succeeded = TRUE;
329 purple_keyring_drop_passwords(tracker->old_kr,
330 purple_keyring_set_inuse_drop_cb, tracker);
334 static void
335 purple_keyring_set_inuse_read_cb(PurpleAccount *account, const gchar *password,
336 GError *error, gpointer _tracker)
338 PurpleKeyringChangeTracker *tracker = _tracker;
339 PurpleKeyringSave save_cb;
341 g_return_if_fail(account != NULL);
342 g_return_if_fail(tracker != NULL);
344 if (tracker->abort) {
345 purple_keyring_set_inuse_save_cb(account, NULL, tracker);
346 return;
349 if (error != NULL) {
350 if (tracker->force == TRUE || g_error_matches(error,
351 PURPLE_KEYRING_ERROR,
352 PURPLE_KEYRING_ERROR_NOPASSWORD))
354 /* Don't save password, and ignore it. */
355 } else {
356 tracker->abort = TRUE;
358 purple_keyring_set_inuse_save_cb(account, error, tracker);
359 return;
362 save_cb = purple_keyring_get_save_password(tracker->new_kr);
363 g_assert(save_cb != NULL);
365 save_cb(account, password, purple_keyring_set_inuse_save_cb, tracker);
368 void
369 purple_keyring_set_inuse(PurpleKeyring *newkeyring, gboolean force,
370 PurpleKeyringSetInUseCallback cb, gpointer data)
372 PurpleKeyring *oldkeyring;
373 PurpleKeyringChangeTracker *tracker;
374 GList *it;
375 PurpleKeyringRead read_cb;
377 if (current_change_tracker != NULL) {
378 GError *error;
379 purple_debug_error("keyring", "There is password migration "
380 "session already running.\n");
381 if (cb == NULL)
382 return;
383 error = g_error_new(PURPLE_KEYRING_ERROR,
384 PURPLE_KEYRING_ERROR_INTERNAL,
385 _("There is a password migration session already "
386 "running."));
387 cb(error, data);
388 g_error_free(error);
389 return;
392 oldkeyring = purple_keyring_get_inuse();
394 if (oldkeyring == newkeyring) {
395 if (purple_debug_is_verbose()) {
396 purple_debug_misc("keyring",
397 "Old and new keyring are the same: %s.\n",
398 (newkeyring != NULL) ?
399 newkeyring->id : "(null)");
401 if (cb != NULL)
402 cb(NULL, data);
403 return;
406 purple_debug_info("keyring", "Attempting to set new keyring: %s.\n",
407 (newkeyring != NULL) ? newkeyring->id : "(null)");
409 if (oldkeyring == NULL) { /* No keyring was set before. */
410 if (purple_debug_is_verbose()) {
411 purple_debug_misc("keyring", "Setting keyring for the "
412 "first time: %s.\n", newkeyring->id);
415 purple_keyring_inuse = newkeyring;
416 g_assert(current_change_tracker == NULL);
417 if (cb != NULL)
418 cb(NULL, data);
419 return;
422 /* Starting a migration. */
424 read_cb = purple_keyring_get_read_password(oldkeyring);
425 g_assert(read_cb != NULL);
427 purple_debug_misc("keyring", "Starting migration from: %s.\n",
428 oldkeyring->id);
430 tracker = g_new0(PurpleKeyringChangeTracker, 1);
431 current_change_tracker = tracker;
433 tracker->cb = cb;
434 tracker->cb_data = data;
435 tracker->new_kr = newkeyring;
436 tracker->old_kr = oldkeyring;
437 tracker->force = force;
439 for (it = purple_accounts_get_all(); it != NULL; it = it->next) {
440 if (tracker->abort) {
441 tracker->finished = TRUE;
442 break;
444 tracker->read_outstanding++;
446 if (it->next == NULL)
447 tracker->finished = TRUE;
449 read_cb(it->data, purple_keyring_set_inuse_read_cb, tracker);
453 void
454 purple_keyring_register(PurpleKeyring *keyring)
456 const gchar *keyring_id;
458 g_return_if_fail(keyring != NULL);
460 keyring_id = purple_keyring_get_id(keyring);
462 purple_debug_info("keyring", "Registering keyring: %s\n",
463 keyring_id ? keyring_id : "(null)");
465 if (purple_keyring_get_id(keyring) == NULL ||
466 purple_keyring_get_name(keyring) == NULL ||
467 purple_keyring_get_read_password(keyring) == NULL ||
468 purple_keyring_get_save_password(keyring) == NULL)
470 purple_debug_error("keyring", "Cannot register %s, some "
471 "required fields are missing.\n",
472 keyring_id ? keyring_id : "(null)");
473 return;
476 if (purple_keyring_find_keyring_by_id(keyring_id) != NULL) {
477 purple_debug_error("keyring",
478 "Keyring is already registered.\n");
479 return;
482 /* If this is the configured keyring, use it. */
483 if (purple_keyring_inuse == NULL &&
484 g_strcmp0(keyring_id, purple_keyring_to_use) == 0)
486 purple_debug_misc("keyring", "Keyring %s matches keyring to "
487 "use, using it.", keyring_id);
488 purple_keyring_set_inuse(keyring, TRUE, NULL, NULL);
491 PURPLE_DBUS_REGISTER_POINTER(keyring, PurpleKeyring);
492 purple_signal_emit(purple_keyring_get_handle(), "keyring-register",
493 keyring_id, keyring);
494 if (purple_debug_is_verbose()) {
495 purple_debug_info("keyring", "Registered keyring: %s.\n",
496 keyring_id);
499 purple_keyring_keyrings = g_list_prepend(purple_keyring_keyrings,
500 keyring);
503 void
504 purple_keyring_unregister(PurpleKeyring *keyring)
506 PurpleKeyring *inuse;
507 PurpleKeyring *fallback;
508 const gchar *keyring_id;
510 g_return_if_fail(keyring != NULL);
512 keyring_id = purple_keyring_get_id(keyring);
514 purple_debug_info("keyring", "Unregistering keyring: %s.\n",
515 keyring_id);
517 purple_signal_emit(purple_keyring_get_handle(), "keyring-unregister",
518 keyring_id, keyring);
519 PURPLE_DBUS_UNREGISTER_POINTER(keyring);
521 inuse = purple_keyring_get_inuse();
522 fallback = purple_keyring_find_keyring_by_id(PURPLE_DEFAULT_KEYRING);
524 if (inuse == keyring) {
525 if (inuse != fallback) {
526 purple_keyring_set_inuse(fallback, TRUE, NULL, NULL);
527 } else {
528 fallback = NULL;
529 purple_keyring_set_inuse(NULL, TRUE, NULL, NULL);
533 purple_keyring_keyrings = g_list_remove(purple_keyring_keyrings,
534 keyring);
537 GList *
538 purple_keyring_get_options(void)
540 GList *options = NULL;
541 GList *it;
542 static gchar currentDisabledName[40];
544 if (purple_keyring_get_inuse() == NULL && purple_keyring_to_use != NULL
545 && purple_keyring_to_use[0] != '\0')
547 g_snprintf(currentDisabledName, sizeof(currentDisabledName),
548 _("%s (disabled)"), purple_keyring_to_use);
550 options = g_list_append(options, currentDisabledName);
551 options = g_list_append(options, purple_keyring_to_use);
554 for (it = purple_keyring_keyrings; it != NULL; it = it->next) {
555 PurpleKeyring *keyring = it->data;
557 options = g_list_append(options,
558 (gpointer)purple_keyring_get_name(keyring));
559 options = g_list_append(options,
560 (gpointer)purple_keyring_get_id(keyring));
563 return options;
567 /**************************************************************************/
568 /* Keyring plugin wrappers */
569 /**************************************************************************/
571 static void
572 purple_keyring_close(PurpleKeyring *keyring)
574 PurpleKeyringClose close_cb;
576 g_return_if_fail(keyring != NULL);
578 if (keyring->is_cancelling) {
579 keyring->close_after_cancel = TRUE;
580 return;
582 if (keyring->is_closing)
583 return;
584 keyring->is_closing = TRUE;
586 close_cb = purple_keyring_get_close_keyring(keyring);
588 if (close_cb != NULL)
589 close_cb();
591 keyring->is_closing = FALSE;
594 static void
595 purple_keyring_cancel_requests(PurpleKeyring *keyring)
597 PurpleKeyringCancelRequests cancel_cb;
599 g_return_if_fail(keyring != NULL);
601 if (keyring->is_cancelling)
602 return;
603 keyring->is_cancelling = TRUE;
605 cancel_cb = purple_keyring_get_cancel_requests(keyring);
607 if (cancel_cb != NULL)
608 cancel_cb();
610 keyring->is_cancelling = FALSE;
612 if (keyring->close_after_cancel) {
613 keyring->close_after_cancel = FALSE;
614 purple_keyring_close(keyring);
618 static void
619 purple_keyring_drop_passwords_save_cb(PurpleAccount *account, GError *error,
620 gpointer _tracker)
622 PurpleKeyringDropTracker *tracker = _tracker;
624 tracker->drop_outstanding--;
626 if (!tracker->finished || tracker->drop_outstanding > 0)
627 return;
629 if (tracker->cb)
630 tracker->cb(tracker->cb_data);
631 g_free(tracker);
634 static void
635 purple_keyring_drop_passwords(PurpleKeyring *keyring,
636 PurpleKeyringDropCallback cb, gpointer data)
638 GList *it;
639 PurpleKeyringSave save_cb;
640 PurpleKeyringDropTracker *tracker;
642 g_return_if_fail(keyring != NULL);
644 save_cb = purple_keyring_get_save_password(keyring);
645 g_assert(save_cb != NULL);
647 tracker = g_new0(PurpleKeyringDropTracker, 1);
648 tracker->cb = cb;
649 tracker->cb_data = data;
651 for (it = purple_accounts_get_all(); it != NULL; it = it->next) {
652 PurpleAccount *account = it->data;
654 tracker->drop_outstanding++;
655 if (it->next == NULL)
656 tracker->finished = TRUE;
658 save_cb(account, NULL, purple_keyring_drop_passwords_save_cb,
659 tracker);
663 gboolean
664 purple_keyring_import_password(PurpleAccount *account, const gchar *keyring_id,
665 const gchar *mode, const gchar *data, GError **error)
667 PurpleKeyring *keyring;
668 PurpleKeyring *inuse;
669 PurpleKeyringImportPassword import;
671 g_return_val_if_fail(account != NULL, FALSE);
673 if (keyring_id == NULL)
674 keyring_id = PURPLE_DEFAULT_KEYRING;
676 purple_debug_misc("keyring", "Importing password for account %s to "
677 "keyring %s.\n", purple_keyring_print_account(account),
678 keyring_id);
680 keyring = purple_keyring_find_keyring_by_id(keyring_id);
681 if (keyring == NULL) {
682 if (error != NULL) {
683 *error = g_error_new(PURPLE_KEYRING_ERROR,
684 PURPLE_KEYRING_ERROR_BACKENDFAIL,
685 _("Specified keyring is not registered."));
687 purple_debug_warning("Keyring", "Specified keyring is not "
688 "registered, cannot import password info for account "
689 "%s.\n", purple_keyring_print_account(account));
690 return FALSE;
693 inuse = purple_keyring_get_inuse();
694 if (inuse == NULL) {
695 PurpleKeyringFailedImport *import;
696 if (error != NULL) {
697 *error = g_error_new(PURPLE_KEYRING_ERROR,
698 PURPLE_KEYRING_ERROR_NOKEYRING,
699 _("No keyring loaded, cannot import password "
700 "info."));
702 purple_debug_warning("Keyring",
703 "No keyring loaded, cannot import password info for "
704 "account %s.\n", purple_keyring_print_account(account));
706 import = g_new0(PurpleKeyringFailedImport, 1);
707 import->keyring_id = g_strdup(keyring_id);
708 import->mode = g_strdup(mode);
709 import->data = g_strdup(data);
710 g_hash_table_insert(purple_keyring_failed_imports, account,
711 import);
712 return FALSE;
715 if (inuse != keyring) {
716 if (error != NULL) {
717 *error = g_error_new(PURPLE_KEYRING_ERROR,
718 PURPLE_KEYRING_ERROR_INTERNAL,
719 _("Specified keyring ID does not match the "
720 "loaded one."));
722 purple_debug_error("keyring",
723 "Specified keyring %s is not currently used (%s). "
724 "Data will be lost.\n", keyring_id,
725 purple_keyring_get_id(inuse));
726 return FALSE;
729 import = purple_keyring_get_import_password(inuse);
730 if (import == NULL) {
731 if (purple_debug_is_verbose()) {
732 purple_debug_misc("Keyring", "Configured keyring "
733 "cannot import password info. This might be "
734 "normal.\n");
736 return TRUE;
739 return import(account, mode, data, error);
742 gboolean
743 purple_keyring_export_password(PurpleAccount *account, const gchar **keyring_id,
744 const gchar **mode, gchar **data, GError **error,
745 GDestroyNotify *destroy)
747 PurpleKeyring *inuse;
748 PurpleKeyringExportPassword export;
750 g_return_val_if_fail(account != NULL, FALSE);
751 g_return_val_if_fail(keyring_id != NULL, FALSE);
752 g_return_val_if_fail(mode != NULL, FALSE);
753 g_return_val_if_fail(data != NULL, FALSE);
754 g_return_val_if_fail(error != NULL, FALSE);
756 inuse = purple_keyring_get_inuse();
758 if (inuse == NULL) {
759 PurpleKeyringFailedImport *import = g_hash_table_lookup(
760 purple_keyring_failed_imports, account);
762 if (import == NULL) {
763 *error = g_error_new(PURPLE_KEYRING_ERROR,
764 PURPLE_KEYRING_ERROR_NOKEYRING,
765 _("No keyring configured, cannot export "
766 "password info."));
767 purple_debug_warning("keyring",
768 "No keyring configured, cannot export password "
769 "info.\n");
770 return FALSE;
771 } else {
772 purple_debug_info("keyring", "No keyring configured, "
773 "getting fallback export data for %s.\n",
774 purple_keyring_print_account(account));
776 *keyring_id = import->keyring_id;
777 *mode = import->mode;
778 *data = g_strdup(import->data);
779 *destroy = (GDestroyNotify)purple_str_wipe;
780 return TRUE;
784 if (purple_debug_is_verbose()) {
785 purple_debug_misc("keyring",
786 "Exporting password for account %s from keyring %s\n",
787 purple_keyring_print_account(account),
788 purple_keyring_get_id(inuse));
791 *keyring_id = purple_keyring_get_id(inuse);
793 export = purple_keyring_get_export_password(inuse);
794 if (export == NULL) {
795 if (purple_debug_is_verbose()) {
796 purple_debug_misc("Keyring", "Configured keyring "
797 "cannot export password info. This might be "
798 "normal.\n");
800 *mode = NULL;
801 *data = NULL;
802 *destroy = NULL;
803 return TRUE;
806 return export(account, mode, data, error, destroy);
809 void
810 purple_keyring_get_password(PurpleAccount *account,
811 PurpleKeyringReadCallback cb, gpointer data)
813 GError *error;
814 PurpleKeyring *inuse;
815 PurpleKeyringRead read_cb;
817 g_return_if_fail(account != NULL);
819 if (purple_keyring_is_quitting) {
820 purple_debug_error("keyring", "Cannot request a password while "
821 "quitting.\n");
822 if (cb == NULL)
823 return;
824 error = g_error_new(PURPLE_KEYRING_ERROR,
825 PURPLE_KEYRING_ERROR_INTERNAL,
826 _("Cannot request a password while quitting."));
827 cb(account, NULL, error, data);
828 g_error_free(error);
829 return;
832 inuse = purple_keyring_get_inuse();
834 if (inuse == NULL) {
835 purple_debug_error("keyring", "No keyring configured.\n");
836 if (cb == NULL)
837 return;
839 error = g_error_new(PURPLE_KEYRING_ERROR,
840 PURPLE_KEYRING_ERROR_NOKEYRING,
841 _("No keyring configured."));
842 cb(account, NULL, error, data);
843 g_error_free(error);
844 return;
847 read_cb = purple_keyring_get_read_password(inuse);
848 g_assert(read_cb != NULL);
850 purple_debug_info("keyring", "Reading password for account %s...\n",
851 purple_keyring_print_account(account));
852 read_cb(account, cb, data);
855 static void
856 purple_keyring_set_password_save_cb(PurpleAccount *account, GError *error,
857 gpointer _set_data)
859 PurpleKeyringSetPasswordData *set_data = _set_data;
861 g_return_if_fail(account != NULL);
862 g_return_if_fail(set_data != NULL);
864 if (error == NULL && purple_debug_is_verbose()) {
865 purple_debug_misc("keyring", "Password for account %s "
866 "saved successfully.\n",
867 purple_keyring_print_account(account));
868 } else if (purple_debug_is_verbose()) {
869 purple_debug_warning("keyring", "Password for account %s "
870 "not saved successfully.\n",
871 purple_keyring_print_account(account));
874 if (error != NULL) {
875 purple_notify_error(NULL, _("Keyrings"),
876 _("Failed to save a password in keyring."),
877 error->message, NULL);
880 if (set_data->cb != NULL)
881 set_data->cb(account, error, set_data->cb_data);
882 g_free(set_data);
885 void
886 purple_keyring_set_password(PurpleAccount *account, const gchar *password,
887 PurpleKeyringSaveCallback cb, gpointer data)
889 GError *error;
890 PurpleKeyring *inuse;
891 PurpleKeyringSave save_cb;
892 PurpleKeyringSetPasswordData *set_data;
894 g_return_if_fail(account != NULL);
896 if (purple_keyring_is_quitting) {
897 purple_debug_error("keyring", "Cannot save a password while "
898 "quitting.\n");
899 if (cb == NULL)
900 return;
901 error = g_error_new(PURPLE_KEYRING_ERROR,
902 PURPLE_KEYRING_ERROR_INTERNAL,
903 _("Cannot save a password while quitting."));
904 cb(account, error, data);
905 g_error_free(error);
906 return;
909 if (current_change_tracker != NULL) {
910 purple_debug_error("keyring", "Cannot save a password during "
911 "password migration.\n");
912 if (cb == NULL)
913 return;
914 error = g_error_new(PURPLE_KEYRING_ERROR,
915 PURPLE_KEYRING_ERROR_INTERNAL,
916 _("Cannot save a password during password migration."));
917 cb(account, error, data);
918 g_error_free(error);
919 return;
922 inuse = purple_keyring_get_inuse();
923 if (inuse == NULL) {
924 if (cb == NULL)
925 return;
926 error = g_error_new(PURPLE_KEYRING_ERROR,
927 PURPLE_KEYRING_ERROR_NOKEYRING,
928 _("No keyring configured."));
929 cb(account, error, data);
930 g_error_free(error);
931 return;
934 save_cb = purple_keyring_get_save_password(inuse);
935 g_assert(save_cb != NULL);
937 set_data = g_new(PurpleKeyringSetPasswordData, 1);
938 set_data->cb = cb;
939 set_data->cb_data = data;
940 purple_debug_info("keyring", "%s password for account %s...\n",
941 (password ? "Saving" : "Removing"),
942 purple_keyring_print_account(account));
943 save_cb(account, password, purple_keyring_set_password_save_cb, set_data);
946 PurpleRequestFields *
947 purple_keyring_read_settings(void)
949 PurpleKeyring *inuse;
950 PurpleKeyringReadSettings read_settings;
952 if (purple_keyring_is_quitting || current_change_tracker != NULL) {
953 purple_debug_error("keyring", "Cannot read settngs at the "
954 "moment.\n");
955 return NULL;
958 inuse = purple_keyring_get_inuse();
959 if (inuse == NULL) {
960 purple_debug_error("keyring", "No keyring in use.\n");
961 return NULL;
964 read_settings = purple_keyring_get_read_settings(inuse);
965 if (read_settings == NULL)
966 return NULL;
967 return read_settings();
970 gboolean
971 purple_keyring_apply_settings(void *notify_handle, PurpleRequestFields *fields)
973 PurpleKeyring *inuse;
974 PurpleKeyringApplySettings apply_settings;
976 g_return_val_if_fail(fields != NULL, FALSE);
978 if (purple_keyring_is_quitting || current_change_tracker != NULL) {
979 purple_debug_error("keyring", "Cannot apply settngs at the "
980 "moment.\n");
981 return FALSE;
984 inuse = purple_keyring_get_inuse();
985 if (inuse == NULL) {
986 purple_debug_error("keyring", "No keyring in use.\n");
987 return FALSE;
990 apply_settings = purple_keyring_get_apply_settings(inuse);
991 if (apply_settings == NULL) {
992 purple_debug_warning("keyring", "Applying settings not "
993 "supported.\n");
994 return FALSE;
996 return apply_settings(notify_handle, fields);
999 /**************************************************************************/
1000 /* PurpleKeyring accessors */
1001 /**************************************************************************/
1003 PurpleKeyring *
1004 purple_keyring_new(void)
1006 return g_new0(PurpleKeyring, 1);
1009 void
1010 purple_keyring_free(PurpleKeyring *keyring)
1012 g_return_if_fail(keyring != NULL);
1014 g_free(keyring->name);
1015 g_free(keyring->id);
1016 g_free(keyring);
1019 const gchar *
1020 purple_keyring_get_name(const PurpleKeyring *keyring)
1022 g_return_val_if_fail(keyring != NULL, NULL);
1024 return keyring->name;
1027 const gchar *
1028 purple_keyring_get_id(const PurpleKeyring *keyring)
1030 g_return_val_if_fail(keyring != NULL, NULL);
1032 return keyring->id;
1035 PurpleKeyringRead
1036 purple_keyring_get_read_password(const PurpleKeyring *keyring)
1038 g_return_val_if_fail(keyring != NULL, NULL);
1040 return keyring->read_password;
1043 PurpleKeyringSave
1044 purple_keyring_get_save_password(const PurpleKeyring *keyring)
1046 g_return_val_if_fail(keyring != NULL, NULL);
1048 return keyring->save_password;
1051 PurpleKeyringCancelRequests
1052 purple_keyring_get_cancel_requests(const PurpleKeyring *keyring)
1054 g_return_val_if_fail(keyring != NULL, NULL);
1056 return keyring->cancel_requests;
1059 PurpleKeyringClose
1060 purple_keyring_get_close_keyring(const PurpleKeyring *keyring)
1062 g_return_val_if_fail(keyring != NULL, NULL);
1064 return keyring->close_keyring;
1067 PurpleKeyringImportPassword
1068 purple_keyring_get_import_password(const PurpleKeyring *keyring)
1070 g_return_val_if_fail(keyring != NULL, NULL);
1072 return keyring->import_password;
1075 PurpleKeyringExportPassword
1076 purple_keyring_get_export_password(const PurpleKeyring *keyring)
1078 g_return_val_if_fail(keyring != NULL, NULL);
1080 return keyring->export_password;
1083 PurpleKeyringReadSettings
1084 purple_keyring_get_read_settings(const PurpleKeyring *keyring)
1086 g_return_val_if_fail(keyring != NULL, NULL);
1088 return keyring->read_settings;
1091 PurpleKeyringApplySettings
1092 purple_keyring_get_apply_settings(const PurpleKeyring *keyring)
1094 g_return_val_if_fail(keyring != NULL, NULL);
1096 return keyring->apply_settings;
1099 void
1100 purple_keyring_set_name(PurpleKeyring *keyring, const gchar *name)
1102 g_return_if_fail(keyring != NULL);
1103 g_return_if_fail(name != NULL);
1105 g_free(keyring->name);
1106 keyring->name = g_strdup(name);
1109 void
1110 purple_keyring_set_id(PurpleKeyring *keyring, const gchar *id)
1112 g_return_if_fail(keyring != NULL);
1113 g_return_if_fail(id != NULL);
1115 g_free(keyring->id);
1116 keyring->id = g_strdup(id);
1119 void
1120 purple_keyring_set_read_password(PurpleKeyring *keyring,
1121 PurpleKeyringRead read_cb)
1123 g_return_if_fail(keyring != NULL);
1124 g_return_if_fail(read_cb != NULL);
1126 keyring->read_password = read_cb;
1129 void
1130 purple_keyring_set_save_password(PurpleKeyring *keyring,
1131 PurpleKeyringSave save_cb)
1133 g_return_if_fail(keyring != NULL);
1134 g_return_if_fail(save_cb != NULL);
1136 keyring->save_password = save_cb;
1139 void
1140 purple_keyring_set_cancel_requests(PurpleKeyring *keyring,
1141 PurpleKeyringCancelRequests cancel_requests)
1143 g_return_if_fail(keyring != NULL);
1145 keyring->cancel_requests = cancel_requests;
1148 void
1149 purple_keyring_set_close_keyring(PurpleKeyring *keyring,
1150 PurpleKeyringClose close_cb)
1152 g_return_if_fail(keyring != NULL);
1154 keyring->close_keyring = close_cb;
1157 void
1158 purple_keyring_set_import_password(PurpleKeyring *keyring,
1159 PurpleKeyringImportPassword import_password)
1161 g_return_if_fail(keyring != NULL);
1163 keyring->import_password = import_password;
1166 void
1167 purple_keyring_set_export_password(PurpleKeyring *keyring,
1168 PurpleKeyringExportPassword export_password)
1170 g_return_if_fail(keyring != NULL);
1172 keyring->export_password = export_password;
1175 void
1176 purple_keyring_set_read_settings(PurpleKeyring *keyring,
1177 PurpleKeyringReadSettings read_settings)
1179 g_return_if_fail(keyring != NULL);
1181 keyring->read_settings = read_settings;
1184 void
1185 purple_keyring_set_apply_settings(PurpleKeyring *keyring,
1186 PurpleKeyringApplySettings apply_settings)
1188 g_return_if_fail(keyring != NULL);
1190 keyring->apply_settings = apply_settings;
1194 /**************************************************************************/
1195 /* Error Codes */
1196 /**************************************************************************/
1198 GQuark purple_keyring_error_domain(void)
1200 return g_quark_from_static_string("libpurple keyring");
1203 /**************************************************************************/
1204 /* Keyring Subsystem */
1205 /**************************************************************************/
1207 static void purple_keyring_core_initialized_cb(void)
1209 if (purple_keyring_inuse == NULL) {
1210 purple_notify_error(NULL, _("Keyrings"),
1211 _("Failed to load selected keyring."),
1212 _("Check your system configuration or select another "
1213 "one in Preferences dialog."), NULL);
1217 static void purple_keyring_core_quitting_cb()
1219 if (current_change_tracker != NULL) {
1220 PurpleKeyringChangeTracker *tracker = current_change_tracker;
1221 tracker->abort = TRUE;
1222 if (tracker->old_kr)
1223 purple_keyring_cancel_requests(tracker->old_kr);
1224 if (current_change_tracker == tracker && tracker->new_kr)
1225 purple_keyring_cancel_requests(tracker->new_kr);
1228 purple_keyring_is_quitting = TRUE;
1229 if (purple_keyring_inuse != NULL)
1230 purple_keyring_cancel_requests(purple_keyring_inuse);
1233 void
1234 purple_keyring_init(void)
1236 const gchar *touse;
1237 GList *plugins, *it;
1239 purple_keyring_keyrings = NULL;
1240 purple_keyring_inuse = NULL;
1242 purple_keyring_failed_imports = g_hash_table_new_full(g_direct_hash,
1243 g_direct_equal, NULL,
1244 (GDestroyNotify)purple_keyring_failed_import_free);
1246 /* void keyring_register(const char *keyring_id,
1247 * PurpleKeyring * keyring);
1249 * A signal called when keyring is registered.
1251 * @param keyring_id The keyring ID.
1252 * @param keyring The keyring.
1254 purple_signal_register(purple_keyring_get_handle(), "keyring-register",
1255 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_STRING,
1256 PURPLE_TYPE_KEYRING);
1258 /* void keyring_unregister(const char *keyring_id,
1259 * PurpleKeyring * keyring);
1261 * A signal called when keyring is unregistered.
1263 * @param keyring_id The keyring ID.
1264 * @param keyring The keyring.
1266 purple_signal_register(purple_keyring_get_handle(), "keyring-unregister",
1267 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_STRING,
1268 PURPLE_TYPE_KEYRING);
1270 /* void password_migration(PurpleAccount* account);
1272 * A signal called, when a password for the account was moved to another
1273 * keyring.
1275 * @param account The account.
1277 purple_signal_register(purple_keyring_get_handle(), "password-migration",
1278 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1, PURPLE_TYPE_ACCOUNT);
1280 touse = purple_prefs_get_string("/purple/keyring/active");
1281 if (touse == NULL) {
1282 purple_prefs_add_none("/purple/keyring");
1283 purple_prefs_add_string("/purple/keyring/active",
1284 PURPLE_DEFAULT_KEYRING);
1285 purple_keyring_to_use = g_strdup(PURPLE_DEFAULT_KEYRING);
1286 } else
1287 purple_keyring_to_use = g_strdup(touse);
1289 purple_keyring_pref_connect();
1291 plugins = purple_plugins_find_all();
1292 for (it = plugins; it != NULL; it = it->next) {
1293 PurplePlugin *plugin = PURPLE_PLUGIN(it->data);
1294 PurplePluginInfo *info = purple_plugin_get_info(plugin);
1296 if (strncmp(purple_plugin_info_get_id(info), "keyring-", 8) != 0)
1297 continue;
1299 if (purple_plugin_is_loaded(plugin))
1300 continue;
1302 if (purple_plugin_load(plugin, NULL)) {
1303 purple_keyring_loaded_plugins = g_list_append(
1304 purple_keyring_loaded_plugins, plugin);
1307 g_list_free(plugins);
1309 if (purple_keyring_inuse == NULL)
1310 purple_debug_error("keyring", "Selected keyring failed to load\n");
1312 purple_signal_connect(purple_get_core(), "core-initialized",
1313 purple_keyring_get_handle(),
1314 PURPLE_CALLBACK(purple_keyring_core_initialized_cb), NULL);
1315 purple_signal_connect(purple_get_core(), "quitting",
1316 purple_keyring_get_handle(),
1317 PURPLE_CALLBACK(purple_keyring_core_quitting_cb), NULL);
1320 void
1321 purple_keyring_uninit(void)
1323 GList *it;
1325 purple_keyring_pref_disconnect();
1327 g_free(purple_keyring_to_use);
1328 purple_keyring_inuse = NULL;
1330 g_hash_table_destroy(purple_keyring_failed_imports);
1331 purple_keyring_failed_imports = NULL;
1333 for (it = g_list_first(purple_keyring_loaded_plugins); it != NULL;
1334 it = g_list_next(it))
1336 PurplePlugin *plugin = PURPLE_PLUGIN(it->data);
1337 if (g_list_find(purple_plugins_get_loaded(), plugin) == NULL)
1338 continue;
1339 purple_plugin_unload(plugin, NULL);
1341 g_list_free(purple_keyring_loaded_plugins);
1342 purple_keyring_loaded_plugins = NULL;
1344 purple_signals_unregister_by_instance(purple_keyring_get_handle());
1345 purple_signals_disconnect_by_handle(purple_keyring_get_handle());
1348 void *
1349 purple_keyring_get_handle(void)
1351 static int handle;
1353 return &handle;
1356 static PurpleKeyring *
1357 purple_keyring_copy(PurpleKeyring *keyring)
1359 PurpleKeyring *keyring_copy;
1361 g_return_val_if_fail(keyring != NULL, NULL);
1363 keyring_copy = purple_keyring_new();
1364 *keyring_copy = *keyring;
1366 keyring_copy->name = g_strdup(keyring->name);
1367 keyring_copy->id = g_strdup(keyring->id);
1369 return keyring_copy;
1372 GType
1373 purple_keyring_get_type(void)
1375 static GType type = 0;
1377 if (type == 0) {
1378 type = g_boxed_type_register_static("PurpleKeyring",
1379 (GBoxedCopyFunc)purple_keyring_copy,
1380 (GBoxedFreeFunc)purple_keyring_free);
1383 return type;