libpurple/keyring.c

branch
soc.2008.masterpassword
changeset 33987
9beebdbf44d6
parent 33983
317cd0a252c2
child 33991
0eb45874d73a
equal deleted inserted replaced
33986:9b1127b96fe8 33987:9beebdbf44d6
1 /** 1 /**
2 * @file keyring.c Keyring plugin API 2 * @file keyring.c Keyring plugin API
3 * @todo 3 * @ingroup core
4 * - purple_keyring_()
5 * - loading : find a way to fallback
6 */ 4 */
7 5
8 /* purple 6 /* purple
9 * 7 *
10 * Purple is the legal property of its developers, whose names are too numerous 8 * Purple is the legal property of its developers, whose names are too numerous
25 * along with this program ; if not, write to the Free Software 23 * along with this program ; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 */ 25 */
28 26
29 #include <glib.h> 27 #include <glib.h>
30 #include <string.h>> 28 #include <string.h>
31 #include "account.h" 29 #include "account.h"
32 #include "keyring.h" 30 #include "keyring.h"
33 #include "signals.h" 31 #include "signals.h"
34 #include "core.h" 32 #include "core.h"
35 #include "debug.h" 33 #include "debug.h"
34
35 typedef struct _PurpleKeyringChangeTracker PurpleKeyringChangeTracker;
36
37 static void purple_keyring_pref_cb(const char *, PurplePrefType, gconstpointer, gpointer);
38 static PurpleKeyring * purple_keyring_find_keyring_by_id(char * id);
39 static void purple_keyring_drop_passwords(const PurpleKeyring * keyring);
40 static void purple_keyring_set_inuse_check_error_cb(const PurpleAccount *,GError *,gpointer);
41 static void purple_keyring_set_inuse_got_pw_cb(PurpleAccount *, gchar *, GError *, gpointer);
42
36 43
37 /******************************************/ 44 /******************************************/
38 /** @name PurpleKeyring */ 45 /** @name PurpleKeyring */
39 /******************************************/ 46 /******************************************/
40 /*@{*/ 47 /*@{*/
54 gpointer r1; /* RESERVED */ 61 gpointer r1; /* RESERVED */
55 gpointer r2; /* RESERVED */ 62 gpointer r2; /* RESERVED */
56 gpointer r3; /* RESERVED */ 63 gpointer r3; /* RESERVED */
57 }; 64 };
58 65
66 struct _PurpleKeyringChangeTracker
67 {
68 GError * error; /* could probably be dropped */
69 PurpleKeyringSetInUseCallback cb;
70 gpointer data;
71 const PurpleKeyring * new;
72 const PurpleKeyring * old; /* we are done when : finished == TRUE && read_outstanding == 0 */
73 int read_outstanding;
74 gboolean finished;
75 gboolean abort;
76 gboolean force;
77 };
59 78
60 /* Constructor */ 79 /* Constructor */
61 PurpleKeyring * 80 PurpleKeyring *
62 purple_keyring_new() 81 purple_keyring_new()
63 { 82 {
266 /*@{*/ 285 /*@{*/
267 286
268 static GList * purple_keyring_keyrings; /* list of available keyrings */ 287 static GList * purple_keyring_keyrings; /* list of available keyrings */
269 static const PurpleKeyring * purple_keyring_inuse; /* keyring being used */ 288 static const PurpleKeyring * purple_keyring_inuse; /* keyring being used */
270 static char * purple_keyring_to_use; 289 static char * purple_keyring_to_use;
271 290 static guint purple_keyring_pref_cb_id;
272 291
273 void 292 void
274 purple_keyring_init() 293 purple_keyring_init()
275 { 294 {
276 PurpleCore * core; 295 PurpleCore * core;
294 NULL, 2, 313 NULL, 2,
295 purple_value_new(PURPLE_TYPE_STRING), /* keyring ID */ 314 purple_value_new(PURPLE_TYPE_STRING), /* keyring ID */
296 purple_value_new(PURPLE_TYPE_BOXED, "PurpleKeyring *")); /* a pointer to the keyring */ 315 purple_value_new(PURPLE_TYPE_BOXED, "PurpleKeyring *")); /* a pointer to the keyring */
297 316
298 /* see what keyring we want to use */ 317 /* see what keyring we want to use */
299
300 purple_prefs_add_string("/purple/keyring/active", "txt");
301 purple_prefs_connect_callback(NULL, "/purple/keyring/active",
302 purple_keyring_pref_cb, NULL);
303
304
305 touse = purple_prefs_get_string("/purple/keyring/active"); 318 touse = purple_prefs_get_string("/purple/keyring/active");
306 319
307 if (touse == NULL) { 320 if (touse == NULL) {
321 purple_prefs_add_none("/purple/keyring");
308 purple_prefs_add_string("/purple/keyring/active", FALLBACK_KEYRING); 322 purple_prefs_add_string("/purple/keyring/active", FALLBACK_KEYRING);
309 purple_keyring_to_use = g_strdup(FALLBACK_KEYRING); 323 purple_keyring_to_use = g_strdup(FALLBACK_KEYRING);
310 324
311 } else { 325 } else {
312 326
313 purple_keyring_to_use = g_strdup(touse); 327 purple_keyring_to_use = g_strdup(touse);
314 } 328 }
315 329
316 purple_prefs_connect_callback(NULL, "/purple/keyring/active", 330 purple_keyring_pref_cb_id = purple_prefs_connect_callback(NULL,
317 purple_keyring_pref_cb, NULL); 331 "/purple/keyring/active", purple_keyring_pref_cb, NULL);
318 332
319 purple_debug_info("keyring", "purple_keyring_init() done, selected keyring is : %s.\n", 333 purple_debug_info("keyring", "purple_keyring_init() done, selected keyring is : %s.\n",
320 purple_keyring_to_use); 334 purple_keyring_to_use);
321 335
322 return; 336 return;
370 384
371 save = purple_keyring_get_save_password(keyring); 385 save = purple_keyring_get_save_password(keyring);
372 386
373 g_return_if_fail(save != NULL); 387 g_return_if_fail(save != NULL);
374 388
375 for (cur = purple_accounts_get_all(); 389 for (cur = purple_accounts_get_all();
376 cur != NULL; 390 cur != NULL;
377 cur = cur->next) 391 cur = cur->next)
378 save(cur->data, "", NULL, NULL, NULL); 392 save(cur->data, NULL, NULL, NULL, NULL);
379 393
380 return; 394 return;
381 } 395 }
382 396
383 struct _PurpleKeyringChangeTracker 397
384 {
385 GError * error; // could probably be dropped
386 PurpleKeyringSetInUseCallback cb;
387 gpointer data;
388 const PurpleKeyring * new;
389 const PurpleKeyring * old; // we are done when : finished == TRUE && read_outstanding == 0
390 int read_outstanding;
391 gboolean finished;
392 gboolean abort;
393 gboolean force;
394 };
395 398
396 static void 399 static void
397 purple_keyring_set_inuse_check_error_cb(const PurpleAccount * account, 400 purple_keyring_set_inuse_check_error_cb(const PurpleAccount * account,
398 GError * error, 401 GError * error,
399 gpointer data) 402 gpointer data)
401 404
402 const char * name; 405 const char * name;
403 PurpleKeyringClose close; 406 PurpleKeyringClose close;
404 struct _PurpleKeyringChangeTracker * tracker; 407 struct _PurpleKeyringChangeTracker * tracker;
405 408
406 tracker = (struct _PurpleKeyringChangeTracker *)data; 409 tracker = (PurpleKeyringChangeTracker *)data;
407 410
408 g_return_if_fail(tracker->abort == FALSE); 411 g_return_if_fail(tracker->abort == FALSE);
409 412
410 tracker->read_outstanding--; 413 tracker->read_outstanding--;
411 414
417 tracker->error = error; 420 tracker->error = error;
418 421
419 switch(error->code) { 422 switch(error->code) {
420 423
421 case ERR_NOCAP : 424 case ERR_NOCAP :
422 g_debug("Keyring could not save password for account %s : %s", name, error->message); 425 purple_debug_info("keyring",
426 "Keyring could not save password for account %s : %s\n",
427 name, error->message);
423 break; 428 break;
424 429
425 case ERR_NOPASSWD : 430 case ERR_NOPASSWD :
426 g_debug("No password found while changing keyring for account %s : %s", 431 purple_debug_info("keyring",
427 name, error->message); 432 "No password found while changing keyring for account %s : %s\n",
433 name, error->message);
428 break; 434 break;
429 435
430 case ERR_NOCHANNEL : 436 case ERR_NOCHANNEL :
431 g_debug("Failed to communicate with backend while changing keyring for account %s : %s Aborting changes.", 437 purple_debug_info("keyring",
432 name, error->message); 438 "Failed to communicate with backend while changing keyring for account %s : %s Aborting changes.\n",
439 name, error->message);
433 tracker->abort = TRUE; 440 tracker->abort = TRUE;
434 break; 441 break;
435 442
436 default : 443 default :
437 g_debug("Unknown error while changing keyring for account %s : %s", name, error->message); 444 purple_debug_info("keyring",
445 "Unknown error while changing keyring for account %s : %s\n",
446 name, error->message);
438 break; 447 break;
439 } 448 }
440 } 449 }
441
442 /* if this was the last one */ 450 /* if this was the last one */
443 if (tracker->finished == TRUE && tracker->read_outstanding == 0) { 451 if (tracker->finished == TRUE && tracker->read_outstanding == 0) {
444 452
445 if (tracker->abort == TRUE && tracker->force == FALSE) { 453 if (tracker->abort == TRUE && tracker->force == FALSE) {
446 454 /**
455 * TODO :
456 * - create faulty keyring to test this code.
457 */
447 if (tracker->cb != NULL) 458 if (tracker->cb != NULL)
448 tracker->cb(tracker->old, FALSE, tracker->error, tracker->data); 459 tracker->cb(tracker->old, FALSE, tracker->error, tracker->data);
449 460
450 purple_keyring_drop_passwords(tracker->new); 461 purple_keyring_drop_passwords(tracker->new);
451 462
452 close = purple_keyring_get_close_keyring(tracker->new); 463 close = purple_keyring_get_close_keyring(tracker->new);
453 if (close != NULL) 464 if (close != NULL)
454 close(NULL); 465 close(NULL);
455 466
467 purple_debug_info("keyring",
468 "Failed to change keyring, aborting");
469
470 /* FIXME : this should maybe be in a callback
471 * cancel the prefs change
472 */
473 purple_prefs_disconnect_callback(purple_keyring_pref_cb_id);
474 purple_prefs_set_string("/purple/keyring/active",
475 purple_keyring_get_id(tracker->old));
476 purple_keyring_pref_cb_id = purple_prefs_connect_callback(NULL,
477 "/purple/keyring/active", purple_keyring_pref_cb, NULL);
478
479
456 } else { 480 } else {
457 close = purple_keyring_get_close_keyring(tracker->old); 481 close = purple_keyring_get_close_keyring(tracker->old);
458 close(&error); 482 if (close != NULL)
459 483 close(&error);
460 tracker->cb(tracker->new, TRUE, error, tracker->data); 484
485 purple_keyring_inuse = tracker->new;
486 purple_keyring_drop_passwords(tracker->old);
487
488 purple_debug_info("keyring",
489 "Successfully changed keyring.\n");
490
491 if (tracker->cb != NULL)
492 tracker->cb(tracker->new, TRUE, error, tracker->data);
461 } 493 }
462 494
463 g_free(tracker); 495 g_free(tracker);
464 } 496 }
497 /**
498 * This is kind of hackish. It will schedule an account save,
499 * and then return because account == NULL.
500 * Another way to do this would be to expose the
501 * schedule_accounts_save() function, but other such functions
502 * are not exposed. So these was done for consistency.
503 */
504 purple_account_set_password_async(NULL, NULL, NULL, NULL, NULL);
505
465 return; 506 return;
466 } 507 }
467 508
468 509
469 static void 510 static void
470 purple_keyring_set_inuse_got_pw_cb(const PurpleAccount * account, 511 purple_keyring_set_inuse_got_pw_cb(PurpleAccount * account,
471 gchar * password, 512 gchar * password,
472 GError * error, 513 GError * error,
473 gpointer data) 514 gpointer data)
474 { 515 {
475 const PurpleKeyring * new; 516 const PurpleKeyring * new;
476 PurpleKeyringSave save; 517 PurpleKeyringSave save;
477 struct _PurpleKeyringChangeTracker * tracker; 518 PurpleKeyringChangeTracker * tracker;
478 519
479 tracker = (struct _PurpleKeyringChangeTracker *)data; 520 tracker = (PurpleKeyringChangeTracker *)data;
480 new = tracker->new; 521 new = tracker->new;
481 522
482 g_return_if_fail(tracker->abort == FALSE); 523 g_return_if_fail(tracker->abort == FALSE);
483 524
484 if (error != NULL) { 525 if (error != NULL) {
495 /* fatal error, abort all */ 536 /* fatal error, abort all */
496 tracker->abort = TRUE; 537 tracker->abort = TRUE;
497 } 538 }
498 539
499 } else { 540 } else {
541
500 542
501 save = purple_keyring_get_save_password(new); 543 save = purple_keyring_get_save_password(new);
502 544
503 if (save != NULL) { 545 if (save != NULL) {
504 /* this test is probably totally useless, since there's no point 546 /* this test is probably totally useless, since there's no point
530 { 572 {
531 GList * cur; 573 GList * cur;
532 const PurpleKeyring * oldkeyring; 574 const PurpleKeyring * oldkeyring;
533 PurpleKeyringRead read = NULL; 575 PurpleKeyringRead read = NULL;
534 PurpleKeyringClose close; 576 PurpleKeyringClose close;
535 struct _PurpleKeyringChangeTracker * tracker; 577 PurpleKeyringChangeTracker * tracker;
536 GError * error = NULL; 578 GError * error = NULL;
537 579
538 purple_debug_info("keyring", "Attempting to set new keyring : %s.\n", 580 if (newkeyring != NULL)
539 newkeyring->id); 581 purple_debug_info("keyring", "Attempting to set new keyring : %s.\n",
582 newkeyring->id);
583 else
584 purple_debug_info("keyring", "Attempting to set new keyring : NULL.\n");
540 585
541 oldkeyring = purple_keyring_get_inuse(); 586 oldkeyring = purple_keyring_get_inuse();
542 587
543 if (oldkeyring != NULL) { 588 if (oldkeyring != NULL) {
544 read = purple_keyring_get_read_password(oldkeyring); 589 read = purple_keyring_get_read_password(oldkeyring);
545 590
546 if (read == NULL) { 591 if (read == NULL) {
592 /*
547 error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP, 593 error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP,
548 "Existing keyring cannot read passwords"); 594 "Existing keyring cannot read passwords");
549 g_debug("Existing keyring cannot read passwords"); 595 */
596 purple_debug_info("keyring", "Existing keyring cannot read passwords");
550 597
551 /* at this point, we know the keyring won't let us 598 /* at this point, we know the keyring won't let us
552 * read passwords, so there no point in copying them. 599 * read passwords, so there no point in copying them.
553 * therefore we just cleanup the old and setup the new 600 * therefore we just cleanup the old and setup the new
554 * one later. 601 * one later.
560 607
561 if (close != NULL) 608 if (close != NULL)
562 close(NULL); /* we can't do much about errors at this point*/ 609 close(NULL); /* we can't do much about errors at this point*/
563 610
564 } else { 611 } else {
565 tracker = g_malloc(sizeof(struct _PurpleKeyringChangeTracker)); 612 tracker = g_malloc(sizeof(PurpleKeyringChangeTracker));
566 oldkeyring = purple_keyring_get_inuse(); 613 oldkeyring = purple_keyring_get_inuse();
567 614
568 tracker->cb = cb; 615 tracker->cb = cb;
569 tracker->data = data; 616 tracker->data = data;
570 tracker->new = newkeyring; 617 tracker->new = newkeyring;
600 } 647 }
601 } 648 }
602 649
603 650
604 651
605 void 652 static void
606 purple_keyring_pref_cb(const char *pref, 653 purple_keyring_pref_cb(const char *pref,
607 PurplePrefType type, 654 PurplePrefType type,
608 gconstpointer id, 655 gconstpointer id,
609 gpointer data) 656 gpointer data)
610 { 657 {
615 g_return_if_fail(id != NULL); 662 g_return_if_fail(id != NULL);
616 663
617 new = purple_keyring_get_keyring_by_id(id); 664 new = purple_keyring_get_keyring_by_id(id);
618 g_return_if_fail(new != NULL); 665 g_return_if_fail(new != NULL);
619 666
620 purple_keyring_set_inuse(new, FALSE, /* XXX */NULL, data); /* FIXME This should have a callback that can cancel the action */ 667 purple_keyring_set_inuse(new, FALSE, NULL, data); /* FIXME Maybe this should have a callback that can cancel the action */
621 668
622 return; 669 return;
623 } 670 }
624 671
625 GList * 672 GList *
626 purple_keyring_get_options() 673 purple_keyring_get_options()
627 { 674 {
628 const GList * keyrings; 675 const GList * keyrings;
629 PurpleKeyring * keyring; 676 PurpleKeyring * keyring;
630 static GList * list = NULL; 677 GList * list = NULL;
631 678
632 for (keyrings = purple_keyring_get_keyrings(); 679 for (keyrings = purple_keyring_get_keyrings();
633 keyrings != NULL; 680 keyrings != NULL;
634 keyrings = keyrings->next) { 681 keyrings = keyrings->next) {
635 682
636 keyring = keyrings->data; 683 keyring = keyrings->data;
637 list = g_list_append(list, keyring->name); 684 list = g_list_append(list, keyring->name);
638 list = g_list_append(list, keyring->id); 685 list = g_list_append(list, keyring->id);
686 purple_debug_info("keyring", "adding pair : %s, %s.\n",
687 keyring->name, keyring->id);
639 } 688 }
640 689
641 return list; 690 return list;
642 } 691 }
643 692
705 PurpleCore * core; 754 PurpleCore * core;
706 const PurpleKeyring * inuse; 755 const PurpleKeyring * inuse;
707 PurpleKeyring * fallback; 756 PurpleKeyring * fallback;
708 const char * keyring_id; 757 const char * keyring_id;
709 758
759 g_return_if_fail(keyring != NULL);
760
761 purple_debug_info("keyring",
762 "Unregistering keyring %s",
763 purple_keyring_get_id(keyring));
764
710 core = purple_get_core(); 765 core = purple_get_core();
711 keyring_id = purple_keyring_get_id(keyring); 766 keyring_id = purple_keyring_get_id(keyring);
712 purple_signal_emit(core, "keyring-unregister", keyring_id, keyring); 767 purple_signal_emit(core, "keyring-unregister", keyring_id, keyring);
713 768
714 inuse = purple_keyring_get_inuse(); 769 inuse = purple_keyring_get_inuse();
770 fallback = purple_keyring_find_keyring_by_id(FALLBACK_KEYRING);
715 771
716 if (inuse == keyring) { 772 if (inuse == keyring) {
717 fallback = purple_keyring_find_keyring_by_id(FALLBACK_KEYRING); 773 if (inuse != fallback) {
718 774 /* TODO : check result ? */
719 /* this is problematic. If it fails, we won't detect it */ 775 purple_keyring_set_inuse(fallback, TRUE, NULL, NULL);
720 purple_keyring_set_inuse(fallback, TRUE, NULL, NULL); 776
777 } else {
778 fallback = NULL;
779 purple_keyring_set_inuse(NULL, TRUE, NULL, NULL);
780 }
721 } 781 }
722 782
723 purple_keyring_keyrings = g_list_remove(purple_keyring_keyrings, 783 purple_keyring_keyrings = g_list_remove(purple_keyring_keyrings,
724 keyring); 784 keyring);
725 785
726 purple_debug_info("keyring", "Keyring %s unregistered", keyring->id); 786 //purple_debug_info("keyring", "Keyring %s unregistered", keyring->id);
727 } 787 }
728 788
729 789
730 /*@}*/ 790 /*@}*/
731 791
745 { 805 {
746 const PurpleKeyring * inuse; 806 const PurpleKeyring * inuse;
747 PurpleKeyringImportPassword import; 807 PurpleKeyringImportPassword import;
748 const char * realid; 808 const char * realid;
749 809
750 purple_debug_info("keyring", "Importing password for account %s (%s).\n", 810 purple_debug_info("keyring", "Importing password for account %s (%s) to keyring %s.\n",
751 purple_account_get_username(account), purple_account_get_protocol_id(account)); 811 purple_account_get_username(account),
812 purple_account_get_protocol_id(account),
813 keyringid);
752 814
753 inuse = purple_keyring_get_inuse(); 815 inuse = purple_keyring_get_inuse();
754 816
755 if (inuse == NULL) { 817 if (inuse == NULL) {
756 *error = g_error_new(ERR_PIDGINKEYRING , ERR_NOKEYRING, 818 *error = g_error_new(ERR_PIDGINKEYRING , ERR_NOKEYRING,
766 * we want to be sure that either : 828 * we want to be sure that either :
767 * - there is a keyringid specified and it matches the one configured 829 * - there is a keyringid specified and it matches the one configured
768 * - or the configured keyring is the fallback, compatible one. 830 * - or the configured keyring is the fallback, compatible one.
769 */ 831 */
770 if ((keyringid != NULL && g_strcmp0(realid, keyringid) != 0) || 832 if ((keyringid != NULL && g_strcmp0(realid, keyringid) != 0) ||
771 g_strcmp0(FALLBACK_KEYRING, realid)) { 833 (keyringid == NULL && g_strcmp0(FALLBACK_KEYRING, realid))) {
834
772 *error = g_error_new(ERR_PIDGINKEYRING , ERR_INVALID, 835 *error = g_error_new(ERR_PIDGINKEYRING , ERR_INVALID,
773 "Specified keyring id does not match the configured one."); 836 "Specified keyring id does not match the configured one.");
774 purple_debug_info("keyring", 837 purple_debug_info("keyring",
775 "Specified keyring id does not match the configured one. Data will be lost."); 838 "Specified keyring id does not match the configured one (%s vs. %s). Data will be lost.\n",
839 keyringid, realid);
776 return FALSE; 840 return FALSE;
777 } 841 }
778 842
779 import = purple_keyring_get_import_password(inuse); 843 import = purple_keyring_get_import_password(inuse);
780 if (import == NULL) { 844 if (import == NULL) {
796 GDestroyNotify * destroy) 860 GDestroyNotify * destroy)
797 { 861 {
798 const PurpleKeyring * inuse; 862 const PurpleKeyring * inuse;
799 PurpleKeyringExportPassword export; 863 PurpleKeyringExportPassword export;
800 864
801 purple_debug_info("keyring", "exporting password.\n");
802
803 inuse = purple_keyring_get_inuse(); 865 inuse = purple_keyring_get_inuse();
804 866
805 if (inuse == NULL) { 867 if (inuse == NULL) {
806 *error = g_error_new(ERR_PIDGINKEYRING , ERR_NOKEYRING, 868 *error = g_error_new(ERR_PIDGINKEYRING , ERR_NOKEYRING,
807 "No keyring configured, cannot import password info"); 869 "No keyring configured, cannot export password info");
808 g_debug("No keyring configured, cannot import password info"); 870 purple_debug_info("keyring",
871 "No keyring configured, cannot export password info");
809 return FALSE; 872 return FALSE;
810 } 873 }
811 874
812 *keyringid = purple_keyring_get_id(inuse); 875 *keyringid = purple_keyring_get_id(inuse);
876
877 purple_debug_info("keyring",
878 "Exporting password for account %s (%s) from keyring %s.\n",
879 purple_account_get_username(account),
880 purple_account_get_protocol_id(account),
881 *keyringid);
813 882
814 if (*keyringid == NULL) { 883 if (*keyringid == NULL) {
815 *error = g_error_new(ERR_PIDGINKEYRING , ERR_INVALID, 884 *error = g_error_new(ERR_PIDGINKEYRING , ERR_INVALID,
816 "Plugin does not have a keyring id"); 885 "Plugin does not have a keyring id");
817 g_debug("Plugin does not have a keyring id"); 886 purple_debug_info("keyring",
887 "Configured keyring does not have a keyring id, cannot export password");
818 return FALSE; 888 return FALSE;
819 } 889 }
820 890
821 export = purple_keyring_get_export_password(inuse); 891 export = purple_keyring_get_export_password(inuse);
822 892
823 if (export == NULL) { 893 if (export == NULL) {
824 *error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP, 894 *error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP,
825 "Keyring cannot export password info."); 895 "Keyring cannot export password info.");
826 g_debug("Keyring cannot export password info. This might be normal"); 896 purple_debug_info("keyring",
897 "Keyring cannot export password info. This might be normal");
827 return FALSE; 898 return FALSE;
828 } 899 }
829 900
830 return export(account, mode, data, error, destroy); 901 return export(account, mode, data, error, destroy);
831 } 902 }

mercurial