Mercurial > pidgin
comparison libpurple/core.c @ 32819:2c6510167895 default tip
propagate from branch 'im.pidgin.pidgin.2.x.y' (head 3315c5dfbd0ad16511bdcf865e5b07c02d07df24)
to branch 'im.pidgin.pidgin' (head cbd1eda6bcbf0565ae7766396bb8f6f419cb6a9a)
| author | Elliott Sales de Andrade <qulogic@pidgin.im> |
|---|---|
| date | Sat, 02 Jun 2012 02:30:49 +0000 |
| parents | da81195f635e |
| children |
comparison
equal
deleted
inserted
replaced
| 32818:01ff09d4a463 | 32819:2c6510167895 |
|---|---|
| 369 #endif /* HAVE_DBUS */ | 369 #endif /* HAVE_DBUS */ |
| 370 | 370 |
| 371 return is_single_instance; | 371 return is_single_instance; |
| 372 } | 372 } |
| 373 | 373 |
| 374 static gboolean | |
| 375 move_and_symlink_dir(const char *path, const char *basename, const char *old_base, const char *new_base, const char *relative) | |
| 376 { | |
| 377 char *new_name = g_build_filename(new_base, basename, NULL); | |
| 378 #ifndef _WIN32 | |
| 379 char *old_name; | |
| 380 #endif | |
| 381 if (g_rename(path, new_name)) | |
| 382 { | |
| 383 purple_debug_error("core", "Error renaming %s to %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 384 path, new_name, g_strerror(errno)); | |
| 385 g_free(new_name); | |
| 386 return FALSE; | |
| 387 } | |
| 388 g_free(new_name); | |
| 389 | |
| 390 #ifndef _WIN32 | |
| 391 /* NOTE: This new_name is relative. */ | |
| 392 new_name = g_build_filename(relative, basename, NULL); | |
| 393 old_name = g_build_filename(old_base, basename, NULL); | |
| 394 if (symlink(new_name, old_name)) | |
| 395 { | |
| 396 purple_debug_warning("core", "Error symlinking %s to %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 397 old_name, new_name, g_strerror(errno)); | |
| 398 } | |
| 399 g_free(old_name); | |
| 400 g_free(new_name); | |
| 401 #endif | |
| 402 | |
| 403 return TRUE; | |
| 404 } | |
| 405 | |
| 406 gboolean | |
| 407 purple_core_migrate(void) | |
| 408 { | |
| 409 const char *user_dir = purple_user_dir(); | |
| 410 char *old_user_dir = g_strconcat(purple_home_dir(), | |
| 411 G_DIR_SEPARATOR_S ".gaim", NULL); | |
| 412 char *status_file; | |
| 413 FILE *fp; | |
| 414 GDir *dir; | |
| 415 GError *err; | |
| 416 const char *entry; | |
| 417 #ifndef _WIN32 | |
| 418 char *logs_dir; | |
| 419 #endif | |
| 420 char *old_icons_dir; | |
| 421 | |
| 422 if (!g_file_test(old_user_dir, G_FILE_TEST_EXISTS)) | |
| 423 { | |
| 424 /* ~/.gaim doesn't exist, so there's nothing to migrate. */ | |
| 425 g_free(old_user_dir); | |
| 426 return TRUE; | |
| 427 } | |
| 428 | |
| 429 status_file = g_strconcat(user_dir, G_DIR_SEPARATOR_S "migrating", NULL); | |
| 430 | |
| 431 if (g_file_test(user_dir, G_FILE_TEST_EXISTS)) | |
| 432 { | |
| 433 /* If we're here, we have both ~/.gaim and .purple. */ | |
| 434 | |
| 435 if (!g_file_test(status_file, G_FILE_TEST_EXISTS)) | |
| 436 { | |
| 437 /* There's no "migrating" status file, | |
| 438 * so ~/.purple is all up to date. */ | |
| 439 g_free(status_file); | |
| 440 g_free(old_user_dir); | |
| 441 return TRUE; | |
| 442 } | |
| 443 } | |
| 444 | |
| 445 /* If we're here, it's time to migrate from ~/.gaim to ~/.purple. */ | |
| 446 | |
| 447 /* Ensure the user directory exists */ | |
| 448 if (!g_file_test(user_dir, G_FILE_TEST_IS_DIR)) | |
| 449 { | |
| 450 if (g_mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) | |
| 451 { | |
| 452 purple_debug_error("core", "Error creating directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 453 user_dir, g_strerror(errno)); | |
| 454 g_free(status_file); | |
| 455 g_free(old_user_dir); | |
| 456 return FALSE; | |
| 457 } | |
| 458 } | |
| 459 | |
| 460 /* This writes ~/.purple/migrating, which allows us to detect | |
| 461 * incomplete migrations and properly retry. */ | |
| 462 if (!(fp = g_fopen(status_file, "w"))) | |
| 463 { | |
| 464 purple_debug_error("core", "Error opening file %s for writing: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 465 status_file, g_strerror(errno)); | |
| 466 g_free(status_file); | |
| 467 g_free(old_user_dir); | |
| 468 return FALSE; | |
| 469 } | |
| 470 fclose(fp); | |
| 471 | |
| 472 /* Open ~/.gaim so we can loop over its contents. */ | |
| 473 err = NULL; | |
| 474 if (!(dir = g_dir_open(old_user_dir, 0, &err))) | |
| 475 { | |
| 476 purple_debug_error("core", "Error opening directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 477 status_file, | |
| 478 (err ? err->message : "Unknown error")); | |
| 479 if (err) | |
| 480 g_error_free(err); | |
| 481 g_free(status_file); | |
| 482 g_free(old_user_dir); | |
| 483 return FALSE; | |
| 484 } | |
| 485 | |
| 486 /* Loop over the contents of ~/.gaim */ | |
| 487 while ((entry = g_dir_read_name(dir))) | |
| 488 { | |
| 489 char *name = g_build_filename(old_user_dir, entry, NULL); | |
| 490 | |
| 491 #ifndef _WIN32 | |
| 492 /* Deal with symlinks... */ | |
| 493 if (g_file_test(name, G_FILE_TEST_IS_SYMLINK)) | |
| 494 { | |
| 495 /* We're only going to duplicate a logs symlink. */ | |
| 496 if (purple_strequal(entry, "logs")) | |
| 497 { | |
| 498 char *link; | |
| 499 err = NULL; | |
| 500 | |
| 501 if ((link = g_file_read_link(name, &err)) == NULL) | |
| 502 { | |
| 503 char *name_utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL); | |
| 504 purple_debug_error("core", "Error reading symlink %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 505 name_utf8 ? name_utf8 : name, err->message); | |
| 506 g_free(name_utf8); | |
| 507 g_error_free(err); | |
| 508 g_free(name); | |
| 509 g_dir_close(dir); | |
| 510 g_free(status_file); | |
| 511 g_free(old_user_dir); | |
| 512 return FALSE; | |
| 513 } | |
| 514 | |
| 515 logs_dir = g_build_filename(user_dir, "logs", NULL); | |
| 516 | |
| 517 if (purple_strequal(link, "../.purple/logs") || | |
| 518 purple_strequal(link, logs_dir)) | |
| 519 { | |
| 520 /* If the symlink points to the new directory, we're | |
| 521 * likely just trying again after a failed migration, | |
| 522 * so there's no need to fail here. */ | |
| 523 g_free(link); | |
| 524 g_free(logs_dir); | |
| 525 continue; | |
| 526 } | |
| 527 | |
| 528 /* In case we are trying again after a failed migration, we need | |
| 529 * to unlink any existing symlink. If it's a directory, this | |
| 530 * will fail, and so will the symlink below, which is good | |
| 531 * because the user should sort things out. */ | |
| 532 g_unlink(logs_dir); | |
| 533 | |
| 534 /* Relative links will most likely still be | |
| 535 * valid from ~/.purple, though it's not | |
| 536 * guaranteed. Oh well. */ | |
| 537 if (symlink(link, logs_dir)) | |
| 538 { | |
| 539 purple_debug_error("core", "Error symlinking %s to %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 540 logs_dir, link, g_strerror(errno)); | |
| 541 g_free(link); | |
| 542 g_free(name); | |
| 543 g_free(logs_dir); | |
| 544 g_dir_close(dir); | |
| 545 g_free(status_file); | |
| 546 g_free(old_user_dir); | |
| 547 return FALSE; | |
| 548 } | |
| 549 | |
| 550 g_free(link); | |
| 551 g_free(logs_dir); | |
| 552 continue; | |
| 553 } | |
| 554 | |
| 555 /* Ignore all other symlinks. */ | |
| 556 continue; | |
| 557 } | |
| 558 #endif | |
| 559 | |
| 560 /* Deal with directories... */ | |
| 561 if (g_file_test(name, G_FILE_TEST_IS_DIR)) | |
| 562 { | |
| 563 if (purple_strequal(entry, "icons")) | |
| 564 { | |
| 565 /* This is a special case for the Album plugin, which | |
| 566 * stores data in the icons folder. We're not copying | |
| 567 * the icons directory over because previous bugs | |
| 568 * meant that it filled up with junk for many users. | |
| 569 * This is a great time to purge it. */ | |
| 570 | |
| 571 GDir *icons_dir; | |
| 572 char *new_icons_dir; | |
| 573 const char *icons_entry; | |
| 574 | |
| 575 err = NULL; | |
| 576 if (!(icons_dir = g_dir_open(name, 0, &err))) | |
| 577 { | |
| 578 purple_debug_error("core", "Error opening directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 579 name, | |
| 580 (err ? err->message : "Unknown error")); | |
| 581 if (err) | |
| 582 g_error_free(err); | |
| 583 g_free(name); | |
| 584 g_dir_close(dir); | |
| 585 g_free(status_file); | |
| 586 g_free(old_user_dir); | |
| 587 return FALSE; | |
| 588 } | |
| 589 | |
| 590 new_icons_dir = g_build_filename(user_dir, "icons", NULL); | |
| 591 /* Ensure the new icon directory exists */ | |
| 592 if (!g_file_test(new_icons_dir, G_FILE_TEST_IS_DIR)) | |
| 593 { | |
| 594 if (g_mkdir(new_icons_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) | |
| 595 { | |
| 596 purple_debug_error("core", "Error creating directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 597 new_icons_dir, g_strerror(errno)); | |
| 598 g_free(new_icons_dir); | |
| 599 g_dir_close(icons_dir); | |
| 600 g_free(name); | |
| 601 g_dir_close(dir); | |
| 602 g_free(status_file); | |
| 603 g_free(old_user_dir); | |
| 604 return FALSE; | |
| 605 } | |
| 606 } | |
| 607 | |
| 608 while ((icons_entry = g_dir_read_name(icons_dir))) | |
| 609 { | |
| 610 char *icons_name = g_build_filename(name, icons_entry, NULL); | |
| 611 | |
| 612 if (g_file_test(icons_name, G_FILE_TEST_IS_DIR)) | |
| 613 { | |
| 614 if (!move_and_symlink_dir(icons_name, icons_entry, | |
| 615 name, new_icons_dir, "../../.purple/icons")) | |
| 616 { | |
| 617 g_free(icons_name); | |
| 618 g_free(new_icons_dir); | |
| 619 g_dir_close(icons_dir); | |
| 620 g_free(name); | |
| 621 g_dir_close(dir); | |
| 622 g_free(status_file); | |
| 623 g_free(old_user_dir); | |
| 624 return FALSE; | |
| 625 } | |
| 626 } | |
| 627 g_free(icons_name); | |
| 628 } | |
| 629 | |
| 630 g_dir_close(icons_dir); | |
| 631 } | |
| 632 else if (purple_strequal(entry, "plugins")) | |
| 633 { | |
| 634 /* Do nothing, because we broke plugin compatibility. | |
| 635 * This means that the plugins directory gets left behind. */ | |
| 636 } | |
| 637 else | |
| 638 { | |
| 639 /* All other directories are moved and symlinked. */ | |
| 640 if (!move_and_symlink_dir(name, entry, old_user_dir, user_dir, "../.purple")) | |
| 641 { | |
| 642 g_free(name); | |
| 643 g_dir_close(dir); | |
| 644 g_free(status_file); | |
| 645 g_free(old_user_dir); | |
| 646 return FALSE; | |
| 647 } | |
| 648 } | |
| 649 } | |
| 650 else if (g_file_test(name, G_FILE_TEST_IS_REGULAR)) | |
| 651 { | |
| 652 /* Regular files are copied. */ | |
| 653 | |
| 654 char *new_name; | |
| 655 FILE *new_file; | |
| 656 | |
| 657 if (!(fp = g_fopen(name, "rb"))) | |
| 658 { | |
| 659 purple_debug_error("core", "Error opening file %s for reading: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 660 name, g_strerror(errno)); | |
| 661 g_free(name); | |
| 662 g_dir_close(dir); | |
| 663 g_free(status_file); | |
| 664 g_free(old_user_dir); | |
| 665 return FALSE; | |
| 666 } | |
| 667 | |
| 668 new_name = g_build_filename(user_dir, entry, NULL); | |
| 669 if (!(new_file = g_fopen(new_name, "wb"))) | |
| 670 { | |
| 671 purple_debug_error("core", "Error opening file %s for writing: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 672 new_name, g_strerror(errno)); | |
| 673 fclose(fp); | |
| 674 g_free(new_name); | |
| 675 g_free(name); | |
| 676 g_dir_close(dir); | |
| 677 g_free(status_file); | |
| 678 g_free(old_user_dir); | |
| 679 return FALSE; | |
| 680 } | |
| 681 | |
| 682 while (!feof(fp)) | |
| 683 { | |
| 684 unsigned char buf[256]; | |
| 685 size_t size; | |
| 686 | |
| 687 size = fread(buf, 1, sizeof(buf), fp); | |
| 688 if (size != sizeof(buf) && !feof(fp)) | |
| 689 { | |
| 690 purple_debug_error("core", "Error reading %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 691 name, g_strerror(errno)); | |
| 692 fclose(new_file); | |
| 693 fclose(fp); | |
| 694 g_free(new_name); | |
| 695 g_free(name); | |
| 696 g_dir_close(dir); | |
| 697 g_free(status_file); | |
| 698 g_free(old_user_dir); | |
| 699 return FALSE; | |
| 700 } | |
| 701 | |
| 702 if (!fwrite(buf, size, 1, new_file) && ferror(new_file) != 0) | |
| 703 { | |
| 704 purple_debug_error("core", "Error writing %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 705 new_name, g_strerror(errno)); | |
| 706 fclose(new_file); | |
| 707 fclose(fp); | |
| 708 g_free(new_name); | |
| 709 g_free(name); | |
| 710 g_dir_close(dir); | |
| 711 g_free(status_file); | |
| 712 g_free(old_user_dir); | |
| 713 return FALSE; | |
| 714 } | |
| 715 } | |
| 716 | |
| 717 if (fclose(new_file)) | |
| 718 { | |
| 719 purple_debug_error("core", "Error writing: %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 720 new_name, g_strerror(errno)); | |
| 721 } | |
| 722 if (fclose(fp)) | |
| 723 { | |
| 724 purple_debug_warning("core", "Error closing %s: %s\n", | |
| 725 name, g_strerror(errno)); | |
| 726 } | |
| 727 g_free(new_name); | |
| 728 } | |
| 729 else | |
| 730 purple_debug_warning("core", "Not a regular file or directory: %s\n", name); | |
| 731 | |
| 732 g_free(name); | |
| 733 } | |
| 734 | |
| 735 /* The migration was successful, so delete the status file. */ | |
| 736 if (g_unlink(status_file)) | |
| 737 { | |
| 738 purple_debug_error("core", "Error unlinking file %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n", | |
| 739 status_file, g_strerror(errno)); | |
| 740 g_free(status_file); | |
| 741 return FALSE; | |
| 742 } | |
| 743 | |
| 744 old_icons_dir = g_build_filename(old_user_dir, "icons", NULL); | |
| 745 _purple_buddy_icon_set_old_icons_dir(old_icons_dir); | |
| 746 g_free(old_icons_dir); | |
| 747 | |
| 748 g_free(old_user_dir); | |
| 749 | |
| 750 g_free(status_file); | |
| 751 return TRUE; | |
| 752 } | |
| 753 | |
| 754 GHashTable* purple_core_get_ui_info() { | 374 GHashTable* purple_core_get_ui_info() { |
| 755 PurpleCoreUiOps *ops = purple_core_get_ui_ops(); | 375 PurpleCoreUiOps *ops = purple_core_get_ui_ops(); |
| 756 | 376 |
| 757 if(NULL == ops || NULL == ops->get_ui_info) | 377 if(NULL == ops || NULL == ops->get_ui_info) |
| 758 return NULL; | 378 return NULL; |
