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
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
30 #include "dbus-maybe.h"
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
;
47 gboolean is_cancelling
;
48 gboolean close_after_cancel
;
54 PurpleKeyringSetInUseCallback cb
;
56 PurpleKeyring
*new_kr
;
57 PurpleKeyring
*old_kr
;
60 * We are done when finished is positive and read_outstanding is zero.
68 } PurpleKeyringChangeTracker
;
70 typedef void (*PurpleKeyringDropCallback
)(gpointer data
);
74 PurpleKeyringDropCallback cb
;
79 } PurpleKeyringDropTracker
;
83 PurpleKeyringSaveCallback cb
;
85 } PurpleKeyringSetPasswordData
;
92 } PurpleKeyringFailedImport
;
95 purple_keyring_change_tracker_free(PurpleKeyringChangeTracker
*tracker
)
98 g_error_free(tracker
->error
);
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
);
114 purple_keyring_close(PurpleKeyring
*keyring
);
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
;
136 purple_keyring_print_account(PurpleAccount
*account
)
138 static gchar print_buff
[100];
140 if (account
== NULL
) {
141 g_snprintf(print_buff
, 100, "(null)");
145 g_snprintf(print_buff
, 100, "%s:%s",
146 purple_account_get_protocol_id(account
),
147 purple_account_get_username(account
));
151 /**************************************************************************/
152 /* Setting used keyrings */
153 /**************************************************************************/
156 purple_keyring_find_keyring_by_id(const gchar
*id
)
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)
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
);
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
);
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;
206 purple_keyring_get_inuse(void)
208 return purple_keyring_inuse
;
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
);
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
);
256 purple_keyring_set_inuse_save_cb(PurpleAccount
*account
, GError
*error
,
259 PurpleKeyringChangeTracker
*tracker
= _tracker
;
261 g_return_if_fail(account
!= NULL
);
262 g_return_if_fail(tracker
!= NULL
);
264 tracker
->read_outstanding
--;
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
),
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
);
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",
319 if (!tracker
->finished
|| tracker
->read_outstanding
> 0)
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
);
328 tracker
->succeeded
= TRUE
;
329 purple_keyring_drop_passwords(tracker
->old_kr
,
330 purple_keyring_set_inuse_drop_cb
, tracker
);
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
);
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. */
356 tracker
->abort
= TRUE
;
358 purple_keyring_set_inuse_save_cb(account
, error
, tracker
);
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
);
369 purple_keyring_set_inuse(PurpleKeyring
*newkeyring
, gboolean force
,
370 PurpleKeyringSetInUseCallback cb
, gpointer data
)
372 PurpleKeyring
*oldkeyring
;
373 PurpleKeyringChangeTracker
*tracker
;
375 PurpleKeyringRead read_cb
;
377 if (current_change_tracker
!= NULL
) {
379 purple_debug_error("keyring", "There is password migration "
380 "session already running.\n");
383 error
= g_error_new(PURPLE_KEYRING_ERROR
,
384 PURPLE_KEYRING_ERROR_INTERNAL
,
385 _("There is a password migration session already "
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)");
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
);
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",
430 tracker
= g_new0(PurpleKeyringChangeTracker
, 1);
431 current_change_tracker
= tracker
;
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
;
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
);
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)");
476 if (purple_keyring_find_keyring_by_id(keyring_id
) != NULL
) {
477 purple_debug_error("keyring",
478 "Keyring is already registered.\n");
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",
499 purple_keyring_keyrings
= g_list_prepend(purple_keyring_keyrings
,
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",
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
);
529 purple_keyring_set_inuse(NULL
, TRUE
, NULL
, NULL
);
533 purple_keyring_keyrings
= g_list_remove(purple_keyring_keyrings
,
538 purple_keyring_get_options(void)
540 GList
*options
= NULL
;
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
));
567 /**************************************************************************/
568 /* Keyring plugin wrappers */
569 /**************************************************************************/
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
;
582 if (keyring
->is_closing
)
584 keyring
->is_closing
= TRUE
;
586 close_cb
= purple_keyring_get_close_keyring(keyring
);
588 if (close_cb
!= NULL
)
591 keyring
->is_closing
= FALSE
;
595 purple_keyring_cancel_requests(PurpleKeyring
*keyring
)
597 PurpleKeyringCancelRequests cancel_cb
;
599 g_return_if_fail(keyring
!= NULL
);
601 if (keyring
->is_cancelling
)
603 keyring
->is_cancelling
= TRUE
;
605 cancel_cb
= purple_keyring_get_cancel_requests(keyring
);
607 if (cancel_cb
!= NULL
)
610 keyring
->is_cancelling
= FALSE
;
612 if (keyring
->close_after_cancel
) {
613 keyring
->close_after_cancel
= FALSE
;
614 purple_keyring_close(keyring
);
619 purple_keyring_drop_passwords_save_cb(PurpleAccount
*account
, GError
*error
,
622 PurpleKeyringDropTracker
*tracker
= _tracker
;
624 tracker
->drop_outstanding
--;
626 if (!tracker
->finished
|| tracker
->drop_outstanding
> 0)
630 tracker
->cb(tracker
->cb_data
);
635 purple_keyring_drop_passwords(PurpleKeyring
*keyring
,
636 PurpleKeyringDropCallback cb
, gpointer data
)
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);
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
,
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
),
680 keyring
= purple_keyring_find_keyring_by_id(keyring_id
);
681 if (keyring
== 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
));
693 inuse
= purple_keyring_get_inuse();
695 PurpleKeyringFailedImport
*import
;
697 *error
= g_error_new(PURPLE_KEYRING_ERROR
,
698 PURPLE_KEYRING_ERROR_NOKEYRING
,
699 _("No keyring loaded, cannot import password "
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
,
715 if (inuse
!= keyring
) {
717 *error
= g_error_new(PURPLE_KEYRING_ERROR
,
718 PURPLE_KEYRING_ERROR_INTERNAL
,
719 _("Specified keyring ID does not match the "
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
));
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 "
739 return import(account
, mode
, data
, error
);
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();
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 "
767 purple_debug_warning("keyring",
768 "No keyring configured, cannot export password "
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
;
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 "
806 return export(account
, mode
, data
, error
, destroy
);
810 purple_keyring_get_password(PurpleAccount
*account
,
811 PurpleKeyringReadCallback cb
, gpointer data
)
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 "
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
);
832 inuse
= purple_keyring_get_inuse();
835 purple_debug_error("keyring", "No keyring configured.\n");
839 error
= g_error_new(PURPLE_KEYRING_ERROR
,
840 PURPLE_KEYRING_ERROR_NOKEYRING
,
841 _("No keyring configured."));
842 cb(account
, NULL
, error
, data
);
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
);
856 purple_keyring_set_password_save_cb(PurpleAccount
*account
, GError
*error
,
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
));
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
);
886 purple_keyring_set_password(PurpleAccount
*account
, const gchar
*password
,
887 PurpleKeyringSaveCallback cb
, gpointer data
)
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 "
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
);
909 if (current_change_tracker
!= NULL
) {
910 purple_debug_error("keyring", "Cannot save a password during "
911 "password migration.\n");
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
);
922 inuse
= purple_keyring_get_inuse();
926 error
= g_error_new(PURPLE_KEYRING_ERROR
,
927 PURPLE_KEYRING_ERROR_NOKEYRING
,
928 _("No keyring configured."));
929 cb(account
, error
, data
);
934 save_cb
= purple_keyring_get_save_password(inuse
);
935 g_assert(save_cb
!= NULL
);
937 set_data
= g_new(PurpleKeyringSetPasswordData
, 1);
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 "
958 inuse
= purple_keyring_get_inuse();
960 purple_debug_error("keyring", "No keyring in use.\n");
964 read_settings
= purple_keyring_get_read_settings(inuse
);
965 if (read_settings
== NULL
)
967 return read_settings();
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 "
984 inuse
= purple_keyring_get_inuse();
986 purple_debug_error("keyring", "No keyring in use.\n");
990 apply_settings
= purple_keyring_get_apply_settings(inuse
);
991 if (apply_settings
== NULL
) {
992 purple_debug_warning("keyring", "Applying settings not "
996 return apply_settings(notify_handle
, fields
);
999 /**************************************************************************/
1000 /* PurpleKeyring accessors */
1001 /**************************************************************************/
1004 purple_keyring_new(void)
1006 return g_new0(PurpleKeyring
, 1);
1010 purple_keyring_free(PurpleKeyring
*keyring
)
1012 g_return_if_fail(keyring
!= NULL
);
1014 g_free(keyring
->name
);
1015 g_free(keyring
->id
);
1020 purple_keyring_get_name(const PurpleKeyring
*keyring
)
1022 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1024 return keyring
->name
;
1028 purple_keyring_get_id(const PurpleKeyring
*keyring
)
1030 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1036 purple_keyring_get_read_password(const PurpleKeyring
*keyring
)
1038 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1040 return keyring
->read_password
;
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
;
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
;
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
);
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
);
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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 /**************************************************************************/
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
);
1234 purple_keyring_init(void)
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
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
);
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)
1299 if (purple_plugin_is_loaded(plugin
))
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
);
1321 purple_keyring_uninit(void)
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
)
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());
1349 purple_keyring_get_handle(void)
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
;
1373 purple_keyring_get_type(void)
1375 static GType type
= 0;
1378 type
= g_boxed_type_register_static("PurpleKeyring",
1379 (GBoxedCopyFunc
)purple_keyring_copy
,
1380 (GBoxedFreeFunc
)purple_keyring_free
);