Fix an incorrect call to soup_message_set_request.
[pidgin-git.git] / libpurple / keyring.c
blob1ce583f9f1f58bcdcdaa6105601fce1c6cbc6ab4
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 "plugins.h"
32 struct _PurpleKeyring
34 gchar *name;
35 gchar *id;
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;
45 gboolean is_closing;
46 gboolean is_cancelling;
47 gboolean close_after_cancel;
50 typedef struct
52 GError *error;
53 PurpleKeyringSetInUseCallback cb;
54 gpointer cb_data;
55 PurpleKeyring *new_kr;
56 PurpleKeyring *old_kr;
59 * We are done when finished is positive and read_outstanding is zero.
61 gboolean finished;
62 int read_outstanding;
64 gboolean abort;
65 gboolean force;
66 gboolean succeeded;
67 } PurpleKeyringChangeTracker;
69 typedef void (*PurpleKeyringDropCallback)(gpointer data);
71 typedef struct
73 PurpleKeyringDropCallback cb;
74 gpointer cb_data;
76 gboolean finished;
77 int drop_outstanding;
78 } PurpleKeyringDropTracker;
80 typedef struct
82 PurpleKeyringSaveCallback cb;
83 gpointer cb_data;
84 } PurpleKeyringSetPasswordData;
86 typedef struct
88 gchar *keyring_id;
89 gchar *mode;
90 gchar *data;
91 } PurpleKeyringFailedImport;
93 static void
94 purple_keyring_change_tracker_free(PurpleKeyringChangeTracker *tracker)
96 if (tracker->error)
97 g_error_free(tracker->error);
98 g_free(tracker);
101 static void
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);
109 g_free(import);
112 static void
113 purple_keyring_close(PurpleKeyring *keyring);
115 static void
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;
134 static const gchar *
135 purple_keyring_print_account(PurpleAccount *account)
137 static gchar print_buff[100];
139 if (account == NULL) {
140 g_snprintf(print_buff, 100, "(null)");
141 return print_buff;
144 g_snprintf(print_buff, 100, "%s:%s",
145 purple_account_get_protocol_id(account),
146 purple_account_get_username(account));
147 return print_buff;
150 /**************************************************************************/
151 /* Setting used keyrings */
152 /**************************************************************************/
154 PurpleKeyring *
155 purple_keyring_find_keyring_by_id(const gchar *id)
157 GList *it;
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)
164 return keyring;
167 return NULL;
170 static void
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);
186 static void
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);
195 static void
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;
204 PurpleKeyring *
205 purple_keyring_get_inuse(void)
207 return purple_keyring_inuse;
210 static void
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);
228 return;
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);
254 static void
255 purple_keyring_set_inuse_save_cb(PurpleAccount *account, GError *error,
256 gpointer _tracker)
258 PurpleKeyringChangeTracker *tracker = _tracker;
260 g_return_if_fail(account != NULL);
261 g_return_if_fail(tracker != NULL);
263 tracker->read_outstanding--;
265 if (error == NULL) {
266 /* no error */
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),
274 error->message);
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);
306 } else {
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",
316 account);
318 if (!tracker->finished || tracker->read_outstanding > 0)
319 return;
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);
326 } else {
327 tracker->succeeded = TRUE;
328 purple_keyring_drop_passwords(tracker->old_kr,
329 purple_keyring_set_inuse_drop_cb, tracker);
333 static void
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);
345 return;
348 if (error != NULL) {
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. */
354 } else {
355 tracker->abort = TRUE;
357 purple_keyring_set_inuse_save_cb(account, error, tracker);
358 return;
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);
367 void
368 purple_keyring_set_inuse(PurpleKeyring *newkeyring, gboolean force,
369 PurpleKeyringSetInUseCallback cb, gpointer data)
371 PurpleKeyring *oldkeyring;
372 PurpleKeyringChangeTracker *tracker;
373 GList *it;
374 PurpleKeyringRead read_cb;
376 if (current_change_tracker != NULL) {
377 GError *error;
378 purple_debug_error("keyring", "There is password migration "
379 "session already running.\n");
380 if (cb == NULL)
381 return;
382 error = g_error_new_literal(
383 PURPLE_KEYRING_ERROR, PURPLE_KEYRING_ERROR_INTERNAL,
384 _("There is a password migration session already "
385 "running."));
386 cb(error, data);
387 g_error_free(error);
388 return;
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)");
400 if (cb != NULL)
401 cb(NULL, data);
402 return;
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);
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_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",
495 keyring_id);
498 purple_keyring_keyrings = g_list_prepend(purple_keyring_keyrings,
499 keyring);
502 void
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",
514 keyring_id);
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);
525 } else {
526 fallback = NULL;
527 purple_keyring_set_inuse(NULL, TRUE, NULL, NULL);
531 purple_keyring_keyrings = g_list_remove(purple_keyring_keyrings,
532 keyring);
535 GList *
536 purple_keyring_get_options(void)
538 GList *options = NULL;
539 GList *it;
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));
561 return options;
565 /**************************************************************************/
566 /* Keyring plugin wrappers */
567 /**************************************************************************/
569 static void
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;
578 return;
580 if (keyring->is_closing)
581 return;
582 keyring->is_closing = TRUE;
584 close_cb = purple_keyring_get_close_keyring(keyring);
586 if (close_cb != NULL)
587 close_cb();
589 keyring->is_closing = FALSE;
592 static void
593 purple_keyring_cancel_requests(PurpleKeyring *keyring)
595 PurpleKeyringCancelRequests cancel_cb;
597 g_return_if_fail(keyring != NULL);
599 if (keyring->is_cancelling)
600 return;
601 keyring->is_cancelling = TRUE;
603 cancel_cb = purple_keyring_get_cancel_requests(keyring);
605 if (cancel_cb != NULL)
606 cancel_cb();
608 keyring->is_cancelling = FALSE;
610 if (keyring->close_after_cancel) {
611 keyring->close_after_cancel = FALSE;
612 purple_keyring_close(keyring);
616 static void
617 purple_keyring_drop_passwords_save_cb(PurpleAccount *account, GError *error,
618 gpointer _tracker)
620 PurpleKeyringDropTracker *tracker = _tracker;
622 tracker->drop_outstanding--;
624 if (!tracker->finished || tracker->drop_outstanding > 0)
625 return;
627 if (tracker->cb)
628 tracker->cb(tracker->cb_data);
629 g_free(tracker);
632 static void
633 purple_keyring_drop_passwords(PurpleKeyring *keyring,
634 PurpleKeyringDropCallback cb, gpointer data)
636 GList *it;
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();
646 if (it == NULL)
647 return;
649 tracker = g_new0(PurpleKeyringDropTracker, 1);
650 tracker->cb = cb;
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,
661 tracker);
665 gboolean
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),
680 keyring_id);
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));
690 return FALSE;
693 inuse = purple_keyring_get_inuse();
694 if (inuse == NULL) {
695 PurpleKeyringFailedImport *import;
696 g_set_error_literal(
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,
708 import);
709 return FALSE;
712 if (inuse != keyring) {
713 g_set_error_literal(
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));
720 return FALSE;
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 "
728 "normal.\n");
730 return TRUE;
733 return import(account, mode, data, error);
736 gboolean
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();
752 if (inuse == NULL) {
753 PurpleKeyringFailedImport *import = g_hash_table_lookup(
754 purple_keyring_failed_imports, account);
756 if (import == NULL) {
757 g_set_error_literal(
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 "
762 "info.\n");
763 return FALSE;
764 } else {
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;
773 return TRUE;
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 "
791 "normal.\n");
793 *mode = NULL;
794 *data = NULL;
795 *destroy = NULL;
796 return TRUE;
799 return export(account, mode, data, error, destroy);
802 void
803 purple_keyring_get_password(PurpleAccount *account,
804 PurpleKeyringReadCallback cb, gpointer data)
806 GError *error;
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 "
814 "quitting.\n");
815 if (cb == NULL)
816 return;
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);
821 g_error_free(error);
822 return;
825 inuse = purple_keyring_get_inuse();
827 if (inuse == NULL) {
828 purple_debug_error("keyring", "No keyring configured.\n");
829 if (cb == NULL)
830 return;
832 error = g_error_new_literal(PURPLE_KEYRING_ERROR,
833 PURPLE_KEYRING_ERROR_NOKEYRING,
834 _("No keyring configured."));
835 cb(account, NULL, error, data);
836 g_error_free(error);
837 return;
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);
848 static void
849 purple_keyring_set_password_save_cb(PurpleAccount *account, GError *error,
850 gpointer _set_data)
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));
867 if (error != NULL) {
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);
875 g_free(set_data);
878 void
879 purple_keyring_set_password(PurpleAccount *account, const gchar *password,
880 PurpleKeyringSaveCallback cb, gpointer data)
882 GError *error;
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 "
891 "quitting.\n");
892 if (cb == NULL)
893 return;
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);
898 g_error_free(error);
899 return;
902 if (current_change_tracker != NULL) {
903 purple_debug_error("keyring", "Cannot save a password during "
904 "password migration.\n");
905 if (cb == NULL)
906 return;
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);
911 g_error_free(error);
912 return;
915 inuse = purple_keyring_get_inuse();
916 if (inuse == NULL) {
917 if (cb == NULL)
918 return;
919 error = g_error_new_literal(PURPLE_KEYRING_ERROR,
920 PURPLE_KEYRING_ERROR_NOKEYRING,
921 _("No keyring configured."));
922 cb(account, error, data);
923 g_error_free(error);
924 return;
927 save_cb = purple_keyring_get_save_password(inuse);
928 g_assert(save_cb != NULL);
930 set_data = g_new(PurpleKeyringSetPasswordData, 1);
931 set_data->cb = cb;
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 "
947 "moment.\n");
948 return NULL;
951 inuse = purple_keyring_get_inuse();
952 if (inuse == NULL) {
953 purple_debug_error("keyring", "No keyring in use.\n");
954 return NULL;
957 read_settings = purple_keyring_get_read_settings(inuse);
958 if (read_settings == NULL)
959 return NULL;
960 return read_settings();
963 gboolean
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 "
973 "moment.\n");
974 return FALSE;
977 inuse = purple_keyring_get_inuse();
978 if (inuse == NULL) {
979 purple_debug_error("keyring", "No keyring in use.\n");
980 return FALSE;
983 apply_settings = purple_keyring_get_apply_settings(inuse);
984 if (apply_settings == NULL) {
985 purple_debug_warning("keyring", "Applying settings not "
986 "supported.\n");
987 return FALSE;
989 return apply_settings(notify_handle, fields);
992 /**************************************************************************/
993 /* PurpleKeyring accessors */
994 /**************************************************************************/
996 PurpleKeyring *
997 purple_keyring_new(void)
999 return g_new0(PurpleKeyring, 1);
1002 void
1003 purple_keyring_free(PurpleKeyring *keyring)
1005 g_return_if_fail(keyring != NULL);
1007 g_free(keyring->name);
1008 g_free(keyring->id);
1009 g_free(keyring);
1012 const gchar *
1013 purple_keyring_get_name(const PurpleKeyring *keyring)
1015 g_return_val_if_fail(keyring != NULL, NULL);
1017 return keyring->name;
1020 const gchar *
1021 purple_keyring_get_id(const PurpleKeyring *keyring)
1023 g_return_val_if_fail(keyring != NULL, NULL);
1025 return keyring->id;
1028 PurpleKeyringRead
1029 purple_keyring_get_read_password(const PurpleKeyring *keyring)
1031 g_return_val_if_fail(keyring != NULL, NULL);
1033 return keyring->read_password;
1036 PurpleKeyringSave
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;
1052 PurpleKeyringClose
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;
1092 void
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);
1102 void
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);
1112 void
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;
1122 void
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;
1132 void
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;
1141 void
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;
1150 void
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;
1159 void
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;
1168 void
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;
1177 void
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 /**************************************************************************/
1188 /* Error Codes */
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);
1226 void
1227 purple_keyring_init(void)
1229 const gchar *touse;
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
1266 * keyring.
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);
1279 } else
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),
1291 "keyring-")) {
1292 continue;
1295 if (purple_plugin_is_loaded(plugin))
1296 continue;
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);
1316 void
1317 purple_keyring_uninit(void)
1319 GList *it;
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)
1334 continue;
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());
1344 void *
1345 purple_keyring_get_handle(void)
1347 static int handle;
1349 return &handle;
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;
1368 GType
1369 purple_keyring_get_type(void)
1371 static GType type = 0;
1373 if (type == 0) {
1374 type = g_boxed_type_register_static("PurpleKeyring",
1375 (GBoxedCopyFunc)purple_keyring_copy,
1376 (GBoxedFreeFunc)purple_keyring_free);
1379 return type;