| 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 /*@{*/ |
| 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) |
| 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) { |
| 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. |
| 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 |
| 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 } |