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
36 PurpleKeyringRead read_password
;
37 PurpleKeyringSave save_password
;
38 PurpleKeyringCancelRequests cancel_requests
;
39 PurpleKeyringClose close_keyring
;
40 PurpleKeyringImportPassword import_password
;
41 PurpleKeyringExportPassword export_password
;
42 PurpleKeyringReadSettings read_settings
;
43 PurpleKeyringApplySettings apply_settings
;
46 gboolean is_cancelling
;
47 gboolean close_after_cancel
;
53 PurpleKeyringSetInUseCallback cb
;
55 PurpleKeyring
*new_kr
;
56 PurpleKeyring
*old_kr
;
59 * We are done when finished is positive and read_outstanding is zero.
67 } PurpleKeyringChangeTracker
;
69 typedef void (*PurpleKeyringDropCallback
)(gpointer data
);
73 PurpleKeyringDropCallback cb
;
78 } PurpleKeyringDropTracker
;
82 PurpleKeyringSaveCallback cb
;
84 } PurpleKeyringSetPasswordData
;
91 } PurpleKeyringFailedImport
;
94 purple_keyring_change_tracker_free(PurpleKeyringChangeTracker
*tracker
)
97 g_error_free(tracker
->error
);
102 purple_keyring_failed_import_free(PurpleKeyringFailedImport
*import
)
104 g_return_if_fail(import
!= NULL
);
106 g_free(import
->keyring_id
);
107 g_free(import
->mode
);
108 purple_str_wipe(import
->data
);
113 purple_keyring_close(PurpleKeyring
*keyring
);
116 purple_keyring_drop_passwords(PurpleKeyring
*keyring
,
117 PurpleKeyringDropCallback cb
, gpointer data
);
119 /* A list of available keyrings */
120 static GList
*purple_keyring_keyrings
= NULL
;
122 /* Keyring being used. */
123 static PurpleKeyring
*purple_keyring_inuse
= NULL
;
125 /* Keyring id marked to use (may not be loadable). */
126 static gchar
*purple_keyring_to_use
= NULL
;
128 static guint purple_keyring_pref_cbid
= 0;
129 static GList
*purple_keyring_loaded_plugins
= NULL
;
130 static PurpleKeyringChangeTracker
*current_change_tracker
= NULL
;
131 static gboolean purple_keyring_is_quitting
= FALSE
;
132 static GHashTable
*purple_keyring_failed_imports
= NULL
;
135 purple_keyring_print_account(PurpleAccount
*account
)
137 static gchar print_buff
[100];
139 if (account
== NULL
) {
140 g_snprintf(print_buff
, 100, "(null)");
144 g_snprintf(print_buff
, 100, "%s:%s",
145 purple_account_get_protocol_id(account
),
146 purple_account_get_username(account
));
150 /**************************************************************************/
151 /* Setting used keyrings */
152 /**************************************************************************/
155 purple_keyring_find_keyring_by_id(const gchar
*id
)
159 for (it
= purple_keyring_keyrings
; it
!= NULL
; it
= it
->next
) {
160 PurpleKeyring
*keyring
= it
->data
;
161 const gchar
*curr_id
= purple_keyring_get_id(keyring
);
163 if (g_strcmp0(id
, curr_id
) == 0)
171 purple_keyring_pref_callback(const gchar
*pref
, PurplePrefType type
,
172 gconstpointer id
, gpointer data
)
174 PurpleKeyring
*new_keyring
;
176 g_return_if_fail(g_strcmp0(pref
, "/purple/keyring/active") == 0);
177 g_return_if_fail(type
== PURPLE_PREF_STRING
);
178 g_return_if_fail(id
!= NULL
);
180 new_keyring
= purple_keyring_find_keyring_by_id(id
);
181 g_return_if_fail(new_keyring
!= NULL
);
183 purple_keyring_set_inuse(new_keyring
, FALSE
, NULL
, NULL
);
187 purple_keyring_pref_connect(void)
189 g_return_if_fail(purple_keyring_pref_cbid
== 0);
191 purple_keyring_pref_cbid
= purple_prefs_connect_callback(NULL
,
192 "/purple/keyring/active", purple_keyring_pref_callback
, NULL
);
196 purple_keyring_pref_disconnect(void)
198 g_return_if_fail(purple_keyring_pref_cbid
!= 0);
200 purple_prefs_disconnect_callback(purple_keyring_pref_cbid
);
201 purple_keyring_pref_cbid
= 0;
205 purple_keyring_get_inuse(void)
207 return purple_keyring_inuse
;
211 purple_keyring_set_inuse_drop_cb(gpointer _tracker
)
213 PurpleKeyringChangeTracker
*tracker
= _tracker
;
215 g_return_if_fail(tracker
!= NULL
);
217 if (tracker
->succeeded
) {
218 purple_keyring_close(tracker
->old_kr
);
220 purple_debug_info("keyring", "Successfully changed keyring.\n");
222 purple_keyring_inuse
= tracker
->new_kr
;
223 current_change_tracker
= NULL
;
225 if (tracker
->cb
!= NULL
)
226 tracker
->cb(NULL
, tracker
->cb_data
);
227 purple_keyring_change_tracker_free(tracker
);
231 purple_debug_error("keyring", "Failed to change keyring, aborting.\n");
233 purple_keyring_close(tracker
->new_kr
);
235 purple_keyring_pref_disconnect();
236 purple_prefs_set_string("/purple/keyring/active",
237 purple_keyring_get_id(tracker
->old_kr
));
238 purple_keyring_pref_connect();
240 current_change_tracker
= NULL
;
242 if (tracker
->error
== NULL
) {
243 tracker
->error
= g_error_new_literal(
244 PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_UNKNOWN
,
245 _("An unknown error has occured."));
248 if (tracker
->cb
!= NULL
)
249 tracker
->cb(tracker
->error
, tracker
->cb_data
);
251 purple_keyring_change_tracker_free(tracker
);
255 purple_keyring_set_inuse_save_cb(PurpleAccount
*account
, GError
*error
,
258 PurpleKeyringChangeTracker
*tracker
= _tracker
;
260 g_return_if_fail(account
!= NULL
);
261 g_return_if_fail(tracker
!= NULL
);
263 tracker
->read_outstanding
--;
267 } else if (g_error_matches(error
, PURPLE_KEYRING_ERROR
,
268 PURPLE_KEYRING_ERROR_NOPASSWORD
))
270 if (purple_debug_is_verbose()) {
271 purple_debug_misc("keyring", "No password found while "
272 "changing keyring for account %s: %s.\n",
273 purple_keyring_print_account(account
),
276 } else if (g_error_matches(error
, PURPLE_KEYRING_ERROR
,
277 PURPLE_KEYRING_ERROR_ACCESSDENIED
))
279 purple_debug_info("keyring", "Access denied while changing "
280 "keyring for account %s: %s.\n",
281 purple_keyring_print_account(account
), error
->message
);
282 tracker
->abort
= TRUE
;
283 if (tracker
->error
!= NULL
)
284 g_error_free(tracker
->error
);
285 tracker
->error
= g_error_copy(error
);
286 } else if (g_error_matches(error
, PURPLE_KEYRING_ERROR
,
287 PURPLE_KEYRING_ERROR_CANCELLED
))
289 purple_debug_info("keyring", "Operation cancelled while "
290 "changing keyring for account %s: %s.\n",
291 purple_keyring_print_account(account
), error
->message
);
292 tracker
->abort
= TRUE
;
293 if (tracker
->error
== NULL
)
294 tracker
->error
= g_error_copy(error
);
295 } else if (g_error_matches(error
, PURPLE_KEYRING_ERROR
,
296 PURPLE_KEYRING_ERROR_BACKENDFAIL
))
298 purple_debug_error("keyring", "Failed to communicate with "
299 "backend while changing keyring for account %s: %s. "
300 "Aborting changes.\n",
301 purple_keyring_print_account(account
), error
->message
);
302 tracker
->abort
= TRUE
;
303 if (tracker
->error
!= NULL
)
304 g_error_free(tracker
->error
);
305 tracker
->error
= g_error_copy(error
);
307 purple_debug_error("keyring", "Unknown error while changing "
308 "keyring for account %s: %s. Aborting changes.\n",
309 purple_keyring_print_account(account
), error
->message
);
310 tracker
->abort
= TRUE
;
311 if (tracker
->error
== NULL
)
312 tracker
->error
= g_error_copy(error
);
315 purple_signal_emit(purple_keyring_get_handle(), "password-migration",
318 if (!tracker
->finished
|| tracker
->read_outstanding
> 0)
321 /* This was the last one. */
322 if (tracker
->abort
&& !tracker
->force
) {
323 tracker
->succeeded
= FALSE
;
324 purple_keyring_drop_passwords(tracker
->new_kr
,
325 purple_keyring_set_inuse_drop_cb
, tracker
);
327 tracker
->succeeded
= TRUE
;
328 purple_keyring_drop_passwords(tracker
->old_kr
,
329 purple_keyring_set_inuse_drop_cb
, tracker
);
334 purple_keyring_set_inuse_read_cb(PurpleAccount
*account
, const gchar
*password
,
335 GError
*error
, gpointer _tracker
)
337 PurpleKeyringChangeTracker
*tracker
= _tracker
;
338 PurpleKeyringSave save_cb
;
340 g_return_if_fail(account
!= NULL
);
341 g_return_if_fail(tracker
!= NULL
);
343 if (tracker
->abort
) {
344 purple_keyring_set_inuse_save_cb(account
, NULL
, tracker
);
349 if (tracker
->force
== TRUE
|| g_error_matches(error
,
350 PURPLE_KEYRING_ERROR
,
351 PURPLE_KEYRING_ERROR_NOPASSWORD
))
353 /* Don't save password, and ignore it. */
355 tracker
->abort
= TRUE
;
357 purple_keyring_set_inuse_save_cb(account
, error
, tracker
);
361 save_cb
= purple_keyring_get_save_password(tracker
->new_kr
);
362 g_assert(save_cb
!= NULL
);
364 save_cb(account
, password
, purple_keyring_set_inuse_save_cb
, tracker
);
368 purple_keyring_set_inuse(PurpleKeyring
*newkeyring
, gboolean force
,
369 PurpleKeyringSetInUseCallback cb
, gpointer data
)
371 PurpleKeyring
*oldkeyring
;
372 PurpleKeyringChangeTracker
*tracker
;
374 PurpleKeyringRead read_cb
;
376 if (current_change_tracker
!= NULL
) {
378 purple_debug_error("keyring", "There is password migration "
379 "session already running.\n");
382 error
= g_error_new_literal(
383 PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_INTERNAL
,
384 _("There is a password migration session already "
391 oldkeyring
= purple_keyring_get_inuse();
393 if (oldkeyring
== newkeyring
) {
394 if (purple_debug_is_verbose()) {
395 purple_debug_misc("keyring",
396 "Old and new keyring are the same: %s.\n",
397 (newkeyring
!= NULL
) ?
398 newkeyring
->id
: "(null)");
405 purple_debug_info("keyring", "Attempting to set new keyring: %s.\n",
406 (newkeyring
!= NULL
) ? newkeyring
->id
: "(null)");
408 if (oldkeyring
== NULL
) { /* No keyring was set before. */
409 if (purple_debug_is_verbose()) {
410 purple_debug_misc("keyring",
411 "Setting keyring for the first time: %s.\n",
412 (newkeyring
!= NULL
) ? newkeyring
->id
: "(null)");
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_signal_emit(purple_keyring_get_handle(), "keyring-register",
492 keyring_id
, keyring
);
493 if (purple_debug_is_verbose()) {
494 purple_debug_info("keyring", "Registered keyring: %s.\n",
498 purple_keyring_keyrings
= g_list_prepend(purple_keyring_keyrings
,
503 purple_keyring_unregister(PurpleKeyring
*keyring
)
505 PurpleKeyring
*inuse
;
506 PurpleKeyring
*fallback
;
507 const gchar
*keyring_id
;
509 g_return_if_fail(keyring
!= NULL
);
511 keyring_id
= purple_keyring_get_id(keyring
);
513 purple_debug_info("keyring", "Unregistering keyring: %s.\n",
516 purple_signal_emit(purple_keyring_get_handle(), "keyring-unregister",
517 keyring_id
, keyring
);
519 inuse
= purple_keyring_get_inuse();
520 fallback
= purple_keyring_find_keyring_by_id(PURPLE_DEFAULT_KEYRING
);
522 if (inuse
== keyring
) {
523 if (inuse
!= fallback
) {
524 purple_keyring_set_inuse(fallback
, TRUE
, NULL
, NULL
);
527 purple_keyring_set_inuse(NULL
, TRUE
, NULL
, NULL
);
531 purple_keyring_keyrings
= g_list_remove(purple_keyring_keyrings
,
536 purple_keyring_get_options(void)
538 GList
*options
= NULL
;
540 static gchar currentDisabledName
[40];
542 if (purple_keyring_get_inuse() == NULL
&& purple_keyring_to_use
!= NULL
543 && purple_keyring_to_use
[0] != '\0')
545 g_snprintf(currentDisabledName
, sizeof(currentDisabledName
),
546 _("%s (disabled)"), purple_keyring_to_use
);
548 options
= g_list_append(options
, currentDisabledName
);
549 options
= g_list_append(options
, purple_keyring_to_use
);
552 for (it
= purple_keyring_keyrings
; it
!= NULL
; it
= it
->next
) {
553 PurpleKeyring
*keyring
= it
->data
;
555 options
= g_list_append(options
,
556 (gpointer
)purple_keyring_get_name(keyring
));
557 options
= g_list_append(options
,
558 (gpointer
)purple_keyring_get_id(keyring
));
565 /**************************************************************************/
566 /* Keyring plugin wrappers */
567 /**************************************************************************/
570 purple_keyring_close(PurpleKeyring
*keyring
)
572 PurpleKeyringClose close_cb
;
574 g_return_if_fail(keyring
!= NULL
);
576 if (keyring
->is_cancelling
) {
577 keyring
->close_after_cancel
= TRUE
;
580 if (keyring
->is_closing
)
582 keyring
->is_closing
= TRUE
;
584 close_cb
= purple_keyring_get_close_keyring(keyring
);
586 if (close_cb
!= NULL
)
589 keyring
->is_closing
= FALSE
;
593 purple_keyring_cancel_requests(PurpleKeyring
*keyring
)
595 PurpleKeyringCancelRequests cancel_cb
;
597 g_return_if_fail(keyring
!= NULL
);
599 if (keyring
->is_cancelling
)
601 keyring
->is_cancelling
= TRUE
;
603 cancel_cb
= purple_keyring_get_cancel_requests(keyring
);
605 if (cancel_cb
!= NULL
)
608 keyring
->is_cancelling
= FALSE
;
610 if (keyring
->close_after_cancel
) {
611 keyring
->close_after_cancel
= FALSE
;
612 purple_keyring_close(keyring
);
617 purple_keyring_drop_passwords_save_cb(PurpleAccount
*account
, GError
*error
,
620 PurpleKeyringDropTracker
*tracker
= _tracker
;
622 tracker
->drop_outstanding
--;
624 if (!tracker
->finished
|| tracker
->drop_outstanding
> 0)
628 tracker
->cb(tracker
->cb_data
);
633 purple_keyring_drop_passwords(PurpleKeyring
*keyring
,
634 PurpleKeyringDropCallback cb
, gpointer data
)
637 PurpleKeyringSave save_cb
;
638 PurpleKeyringDropTracker
*tracker
;
640 g_return_if_fail(keyring
!= NULL
);
642 save_cb
= purple_keyring_get_save_password(keyring
);
643 g_assert(save_cb
!= NULL
);
645 it
= purple_accounts_get_all();
649 tracker
= g_new0(PurpleKeyringDropTracker
, 1);
651 tracker
->cb_data
= data
;
653 for (; it
!= NULL
; it
= it
->next
) {
654 PurpleAccount
*account
= it
->data
;
656 tracker
->drop_outstanding
++;
657 if (it
->next
== NULL
)
658 tracker
->finished
= TRUE
;
660 save_cb(account
, NULL
, purple_keyring_drop_passwords_save_cb
,
666 purple_keyring_import_password(PurpleAccount
*account
, const gchar
*keyring_id
,
667 const gchar
*mode
, const gchar
*data
, GError
**error
)
669 PurpleKeyring
*keyring
;
670 PurpleKeyring
*inuse
;
671 PurpleKeyringImportPassword import
;
673 g_return_val_if_fail(account
!= NULL
, FALSE
);
675 if (keyring_id
== NULL
)
676 keyring_id
= PURPLE_DEFAULT_KEYRING
;
678 purple_debug_misc("keyring", "Importing password for account %s to "
679 "keyring %s.\n", purple_keyring_print_account(account
),
682 keyring
= purple_keyring_find_keyring_by_id(keyring_id
);
683 if (keyring
== NULL
) {
684 g_set_error_literal(error
, PURPLE_KEYRING_ERROR
,
685 PURPLE_KEYRING_ERROR_BACKENDFAIL
,
686 _("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
, PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_NOKEYRING
,
698 _("No keyring loaded, cannot import password info."));
699 purple_debug_warning("Keyring",
700 "No keyring loaded, cannot import password info for "
701 "account %s.\n", purple_keyring_print_account(account
));
703 import
= g_new0(PurpleKeyringFailedImport
, 1);
704 import
->keyring_id
= g_strdup(keyring_id
);
705 import
->mode
= g_strdup(mode
);
706 import
->data
= g_strdup(data
);
707 g_hash_table_insert(purple_keyring_failed_imports
, account
,
712 if (inuse
!= keyring
) {
714 error
, PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_INTERNAL
,
715 _("Specified keyring ID does not match the loaded one."));
716 purple_debug_error("keyring",
717 "Specified keyring %s is not currently used (%s). "
718 "Data will be lost.\n", keyring_id
,
719 purple_keyring_get_id(inuse
));
723 import
= purple_keyring_get_import_password(inuse
);
724 if (import
== NULL
) {
725 if (purple_debug_is_verbose()) {
726 purple_debug_misc("Keyring", "Configured keyring "
727 "cannot import password info. This might be "
733 return import(account
, mode
, data
, error
);
737 purple_keyring_export_password(PurpleAccount
*account
, const gchar
**keyring_id
,
738 const gchar
**mode
, gchar
**data
, GError
**error
,
739 GDestroyNotify
*destroy
)
741 PurpleKeyring
*inuse
;
742 PurpleKeyringExportPassword export
;
744 g_return_val_if_fail(account
!= NULL
, FALSE
);
745 g_return_val_if_fail(keyring_id
!= NULL
, FALSE
);
746 g_return_val_if_fail(mode
!= NULL
, FALSE
);
747 g_return_val_if_fail(data
!= NULL
, FALSE
);
748 g_return_val_if_fail(error
!= NULL
, FALSE
);
750 inuse
= purple_keyring_get_inuse();
753 PurpleKeyringFailedImport
*import
= g_hash_table_lookup(
754 purple_keyring_failed_imports
, account
);
756 if (import
== NULL
) {
758 error
, PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_NOKEYRING
,
759 _("No keyring configured, cannot export password info."));
760 purple_debug_warning("keyring",
761 "No keyring configured, cannot export password "
765 purple_debug_info("keyring", "No keyring configured, "
766 "getting fallback export data for %s.\n",
767 purple_keyring_print_account(account
));
769 *keyring_id
= import
->keyring_id
;
770 *mode
= import
->mode
;
771 *data
= g_strdup(import
->data
);
772 *destroy
= (GDestroyNotify
)purple_str_wipe
;
777 if (purple_debug_is_verbose()) {
778 purple_debug_misc("keyring",
779 "Exporting password for account %s from keyring %s\n",
780 purple_keyring_print_account(account
),
781 purple_keyring_get_id(inuse
));
784 *keyring_id
= purple_keyring_get_id(inuse
);
786 export
= purple_keyring_get_export_password(inuse
);
787 if (export
== NULL
) {
788 if (purple_debug_is_verbose()) {
789 purple_debug_misc("Keyring", "Configured keyring "
790 "cannot export password info. This might be "
799 return export(account
, mode
, data
, error
, destroy
);
803 purple_keyring_get_password(PurpleAccount
*account
,
804 PurpleKeyringReadCallback cb
, gpointer data
)
807 PurpleKeyring
*inuse
;
808 PurpleKeyringRead read_cb
;
810 g_return_if_fail(account
!= NULL
);
812 if (purple_keyring_is_quitting
) {
813 purple_debug_error("keyring", "Cannot request a password while "
817 error
= g_error_new_literal(
818 PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_INTERNAL
,
819 _("Cannot request a password while quitting."));
820 cb(account
, NULL
, error
, data
);
825 inuse
= purple_keyring_get_inuse();
828 purple_debug_error("keyring", "No keyring configured.\n");
832 error
= g_error_new_literal(PURPLE_KEYRING_ERROR
,
833 PURPLE_KEYRING_ERROR_NOKEYRING
,
834 _("No keyring configured."));
835 cb(account
, NULL
, error
, data
);
840 read_cb
= purple_keyring_get_read_password(inuse
);
841 g_assert(read_cb
!= NULL
);
843 purple_debug_info("keyring", "Reading password for account %s...\n",
844 purple_keyring_print_account(account
));
845 read_cb(account
, cb
, data
);
849 purple_keyring_set_password_save_cb(PurpleAccount
*account
, GError
*error
,
852 PurpleKeyringSetPasswordData
*set_data
= _set_data
;
854 g_return_if_fail(account
!= NULL
);
855 g_return_if_fail(set_data
!= NULL
);
857 if (error
== NULL
&& purple_debug_is_verbose()) {
858 purple_debug_misc("keyring", "Password for account %s "
859 "saved successfully.\n",
860 purple_keyring_print_account(account
));
861 } else if (purple_debug_is_verbose()) {
862 purple_debug_warning("keyring", "Password for account %s "
863 "not saved successfully.\n",
864 purple_keyring_print_account(account
));
868 purple_notify_error(NULL
, _("Keyrings"),
869 _("Failed to save a password in keyring."),
870 error
->message
, NULL
);
873 if (set_data
->cb
!= NULL
)
874 set_data
->cb(account
, error
, set_data
->cb_data
);
879 purple_keyring_set_password(PurpleAccount
*account
, const gchar
*password
,
880 PurpleKeyringSaveCallback cb
, gpointer data
)
883 PurpleKeyring
*inuse
;
884 PurpleKeyringSave save_cb
;
885 PurpleKeyringSetPasswordData
*set_data
;
887 g_return_if_fail(account
!= NULL
);
889 if (purple_keyring_is_quitting
) {
890 purple_debug_error("keyring", "Cannot save a password while "
894 error
= g_error_new_literal(
895 PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_INTERNAL
,
896 _("Cannot save a password while quitting."));
897 cb(account
, error
, data
);
902 if (current_change_tracker
!= NULL
) {
903 purple_debug_error("keyring", "Cannot save a password during "
904 "password migration.\n");
907 error
= g_error_new_literal(
908 PURPLE_KEYRING_ERROR
, PURPLE_KEYRING_ERROR_INTERNAL
,
909 _("Cannot save a password during password migration."));
910 cb(account
, error
, data
);
915 inuse
= purple_keyring_get_inuse();
919 error
= g_error_new_literal(PURPLE_KEYRING_ERROR
,
920 PURPLE_KEYRING_ERROR_NOKEYRING
,
921 _("No keyring configured."));
922 cb(account
, error
, data
);
927 save_cb
= purple_keyring_get_save_password(inuse
);
928 g_assert(save_cb
!= NULL
);
930 set_data
= g_new(PurpleKeyringSetPasswordData
, 1);
932 set_data
->cb_data
= data
;
933 purple_debug_info("keyring", "%s password for account %s...\n",
934 (password
? "Saving" : "Removing"),
935 purple_keyring_print_account(account
));
936 save_cb(account
, password
, purple_keyring_set_password_save_cb
, set_data
);
939 PurpleRequestFields
*
940 purple_keyring_read_settings(void)
942 PurpleKeyring
*inuse
;
943 PurpleKeyringReadSettings read_settings
;
945 if (purple_keyring_is_quitting
|| current_change_tracker
!= NULL
) {
946 purple_debug_error("keyring", "Cannot read settngs at the "
951 inuse
= purple_keyring_get_inuse();
953 purple_debug_error("keyring", "No keyring in use.\n");
957 read_settings
= purple_keyring_get_read_settings(inuse
);
958 if (read_settings
== NULL
)
960 return read_settings();
964 purple_keyring_apply_settings(void *notify_handle
, PurpleRequestFields
*fields
)
966 PurpleKeyring
*inuse
;
967 PurpleKeyringApplySettings apply_settings
;
969 g_return_val_if_fail(fields
!= NULL
, FALSE
);
971 if (purple_keyring_is_quitting
|| current_change_tracker
!= NULL
) {
972 purple_debug_error("keyring", "Cannot apply settngs at the "
977 inuse
= purple_keyring_get_inuse();
979 purple_debug_error("keyring", "No keyring in use.\n");
983 apply_settings
= purple_keyring_get_apply_settings(inuse
);
984 if (apply_settings
== NULL
) {
985 purple_debug_warning("keyring", "Applying settings not "
989 return apply_settings(notify_handle
, fields
);
992 /**************************************************************************/
993 /* PurpleKeyring accessors */
994 /**************************************************************************/
997 purple_keyring_new(void)
999 return g_new0(PurpleKeyring
, 1);
1003 purple_keyring_free(PurpleKeyring
*keyring
)
1005 g_return_if_fail(keyring
!= NULL
);
1007 g_free(keyring
->name
);
1008 g_free(keyring
->id
);
1013 purple_keyring_get_name(const PurpleKeyring
*keyring
)
1015 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1017 return keyring
->name
;
1021 purple_keyring_get_id(const PurpleKeyring
*keyring
)
1023 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1029 purple_keyring_get_read_password(const PurpleKeyring
*keyring
)
1031 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1033 return keyring
->read_password
;
1037 purple_keyring_get_save_password(const PurpleKeyring
*keyring
)
1039 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1041 return keyring
->save_password
;
1044 PurpleKeyringCancelRequests
1045 purple_keyring_get_cancel_requests(const PurpleKeyring
*keyring
)
1047 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1049 return keyring
->cancel_requests
;
1053 purple_keyring_get_close_keyring(const PurpleKeyring
*keyring
)
1055 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1057 return keyring
->close_keyring
;
1060 PurpleKeyringImportPassword
1061 purple_keyring_get_import_password(const PurpleKeyring
*keyring
)
1063 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1065 return keyring
->import_password
;
1068 PurpleKeyringExportPassword
1069 purple_keyring_get_export_password(const PurpleKeyring
*keyring
)
1071 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1073 return keyring
->export_password
;
1076 PurpleKeyringReadSettings
1077 purple_keyring_get_read_settings(const PurpleKeyring
*keyring
)
1079 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1081 return keyring
->read_settings
;
1084 PurpleKeyringApplySettings
1085 purple_keyring_get_apply_settings(const PurpleKeyring
*keyring
)
1087 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1089 return keyring
->apply_settings
;
1093 purple_keyring_set_name(PurpleKeyring
*keyring
, const gchar
*name
)
1095 g_return_if_fail(keyring
!= NULL
);
1096 g_return_if_fail(name
!= NULL
);
1098 g_free(keyring
->name
);
1099 keyring
->name
= g_strdup(name
);
1103 purple_keyring_set_id(PurpleKeyring
*keyring
, const gchar
*id
)
1105 g_return_if_fail(keyring
!= NULL
);
1106 g_return_if_fail(id
!= NULL
);
1108 g_free(keyring
->id
);
1109 keyring
->id
= g_strdup(id
);
1113 purple_keyring_set_read_password(PurpleKeyring
*keyring
,
1114 PurpleKeyringRead read_cb
)
1116 g_return_if_fail(keyring
!= NULL
);
1117 g_return_if_fail(read_cb
!= NULL
);
1119 keyring
->read_password
= read_cb
;
1123 purple_keyring_set_save_password(PurpleKeyring
*keyring
,
1124 PurpleKeyringSave save_cb
)
1126 g_return_if_fail(keyring
!= NULL
);
1127 g_return_if_fail(save_cb
!= NULL
);
1129 keyring
->save_password
= save_cb
;
1133 purple_keyring_set_cancel_requests(PurpleKeyring
*keyring
,
1134 PurpleKeyringCancelRequests cancel_requests
)
1136 g_return_if_fail(keyring
!= NULL
);
1138 keyring
->cancel_requests
= cancel_requests
;
1142 purple_keyring_set_close_keyring(PurpleKeyring
*keyring
,
1143 PurpleKeyringClose close_cb
)
1145 g_return_if_fail(keyring
!= NULL
);
1147 keyring
->close_keyring
= close_cb
;
1151 purple_keyring_set_import_password(PurpleKeyring
*keyring
,
1152 PurpleKeyringImportPassword import_password
)
1154 g_return_if_fail(keyring
!= NULL
);
1156 keyring
->import_password
= import_password
;
1160 purple_keyring_set_export_password(PurpleKeyring
*keyring
,
1161 PurpleKeyringExportPassword export_password
)
1163 g_return_if_fail(keyring
!= NULL
);
1165 keyring
->export_password
= export_password
;
1169 purple_keyring_set_read_settings(PurpleKeyring
*keyring
,
1170 PurpleKeyringReadSettings read_settings
)
1172 g_return_if_fail(keyring
!= NULL
);
1174 keyring
->read_settings
= read_settings
;
1178 purple_keyring_set_apply_settings(PurpleKeyring
*keyring
,
1179 PurpleKeyringApplySettings apply_settings
)
1181 g_return_if_fail(keyring
!= NULL
);
1183 keyring
->apply_settings
= apply_settings
;
1187 /**************************************************************************/
1189 /**************************************************************************/
1191 GQuark
purple_keyring_error_domain(void)
1193 return g_quark_from_static_string("libpurple keyring");
1196 /**************************************************************************/
1197 /* Keyring Subsystem */
1198 /**************************************************************************/
1200 static void purple_keyring_core_initialized_cb(void)
1202 if (purple_keyring_inuse
== NULL
) {
1203 purple_notify_error(NULL
, _("Keyrings"),
1204 _("Failed to load selected keyring."),
1205 _("Check your system configuration or select another "
1206 "one in Preferences dialog."), NULL
);
1210 static void purple_keyring_core_quitting_cb()
1212 if (current_change_tracker
!= NULL
) {
1213 PurpleKeyringChangeTracker
*tracker
= current_change_tracker
;
1214 tracker
->abort
= TRUE
;
1215 if (tracker
->old_kr
)
1216 purple_keyring_cancel_requests(tracker
->old_kr
);
1217 if (current_change_tracker
== tracker
&& tracker
->new_kr
)
1218 purple_keyring_cancel_requests(tracker
->new_kr
);
1221 purple_keyring_is_quitting
= TRUE
;
1222 if (purple_keyring_inuse
!= NULL
)
1223 purple_keyring_cancel_requests(purple_keyring_inuse
);
1227 purple_keyring_init(void)
1230 GList
*plugins
, *it
;
1232 purple_keyring_keyrings
= NULL
;
1233 purple_keyring_inuse
= NULL
;
1235 purple_keyring_failed_imports
= g_hash_table_new_full(g_direct_hash
,
1236 g_direct_equal
, NULL
,
1237 (GDestroyNotify
)purple_keyring_failed_import_free
);
1239 /* void keyring_register(const char *keyring_id,
1240 * PurpleKeyring * keyring);
1242 * A signal called when keyring is registered.
1244 * @param keyring_id The keyring ID.
1245 * @param keyring The keyring.
1247 purple_signal_register(purple_keyring_get_handle(), "keyring-register",
1248 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2, G_TYPE_STRING
,
1249 PURPLE_TYPE_KEYRING
);
1251 /* void keyring_unregister(const char *keyring_id,
1252 * PurpleKeyring * keyring);
1254 * A signal called when keyring is unregistered.
1256 * @param keyring_id The keyring ID.
1257 * @param keyring The keyring.
1259 purple_signal_register(purple_keyring_get_handle(), "keyring-unregister",
1260 purple_marshal_VOID__POINTER_POINTER
, G_TYPE_NONE
, 2, G_TYPE_STRING
,
1261 PURPLE_TYPE_KEYRING
);
1263 /* void password_migration(PurpleAccount* account);
1265 * A signal called, when a password for the account was moved to another
1268 * @param account The account.
1270 purple_signal_register(purple_keyring_get_handle(), "password-migration",
1271 purple_marshal_VOID__POINTER
, G_TYPE_NONE
, 1, PURPLE_TYPE_ACCOUNT
);
1273 touse
= purple_prefs_get_string("/purple/keyring/active");
1274 if (touse
== NULL
) {
1275 purple_prefs_add_none("/purple/keyring");
1276 purple_prefs_add_string("/purple/keyring/active",
1277 PURPLE_DEFAULT_KEYRING
);
1278 purple_keyring_to_use
= g_strdup(PURPLE_DEFAULT_KEYRING
);
1280 purple_keyring_to_use
= g_strdup(touse
);
1282 purple_keyring_pref_connect();
1284 plugins
= purple_plugins_find_all();
1285 for (it
= plugins
; it
!= NULL
; it
= it
->next
) {
1286 PurplePlugin
*plugin
= PURPLE_PLUGIN(it
->data
);
1287 GPluginPluginInfo
*info
=
1288 GPLUGIN_PLUGIN_INFO(purple_plugin_get_info(plugin
));
1290 if (!purple_str_has_prefix(gplugin_plugin_info_get_id(info
),
1295 if (purple_plugin_is_loaded(plugin
))
1298 if (purple_plugin_load(plugin
, NULL
)) {
1299 purple_keyring_loaded_plugins
= g_list_append(
1300 purple_keyring_loaded_plugins
, plugin
);
1303 g_list_free(plugins
);
1305 if (purple_keyring_inuse
== NULL
)
1306 purple_debug_error("keyring", "Selected keyring failed to load\n");
1308 purple_signal_connect(purple_get_core(), "core-initialized",
1309 purple_keyring_get_handle(),
1310 PURPLE_CALLBACK(purple_keyring_core_initialized_cb
), NULL
);
1311 purple_signal_connect(purple_get_core(), "quitting",
1312 purple_keyring_get_handle(),
1313 PURPLE_CALLBACK(purple_keyring_core_quitting_cb
), NULL
);
1317 purple_keyring_uninit(void)
1321 purple_keyring_pref_disconnect();
1323 g_free(purple_keyring_to_use
);
1324 purple_keyring_inuse
= NULL
;
1326 g_hash_table_destroy(purple_keyring_failed_imports
);
1327 purple_keyring_failed_imports
= NULL
;
1329 for (it
= g_list_first(purple_keyring_loaded_plugins
); it
!= NULL
;
1330 it
= g_list_next(it
))
1332 PurplePlugin
*plugin
= PURPLE_PLUGIN(it
->data
);
1333 if (g_list_find(purple_plugins_get_loaded(), plugin
) == NULL
)
1335 purple_plugin_unload(plugin
, NULL
);
1337 g_list_free(purple_keyring_loaded_plugins
);
1338 purple_keyring_loaded_plugins
= NULL
;
1340 purple_signals_unregister_by_instance(purple_keyring_get_handle());
1341 purple_signals_disconnect_by_handle(purple_keyring_get_handle());
1345 purple_keyring_get_handle(void)
1352 static PurpleKeyring
*
1353 purple_keyring_copy(PurpleKeyring
*keyring
)
1355 PurpleKeyring
*keyring_copy
;
1357 g_return_val_if_fail(keyring
!= NULL
, NULL
);
1359 keyring_copy
= purple_keyring_new();
1360 *keyring_copy
= *keyring
;
1362 keyring_copy
->name
= g_strdup(keyring
->name
);
1363 keyring_copy
->id
= g_strdup(keyring
->id
);
1365 return keyring_copy
;
1369 purple_keyring_get_type(void)
1371 static GType type
= 0;
1374 type
= g_boxed_type_register_static("PurpleKeyring",
1375 (GBoxedCopyFunc
)purple_keyring_copy
,
1376 (GBoxedFreeFunc
)purple_keyring_free
);