Mercurial > pidgin.yaz
comparison libpurple/core.c @ 32301:609e3855f36d
propagate from branch 'im.pidgin.pidgin' (head 4fb1347ba91ca1ac8b6f5ad029c1ed0f1b6e60a2)
to branch 'im.pidgin.pidgin.next.major' (head 675a312342374865dae98f559ff532b62c47a350)
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 18 Apr 2011 06:32:04 +0000 |
parents | da81195f635e |
children |
comparison
equal
deleted
inserted
replaced
31923:29f4dbdb1d0f | 32301:609e3855f36d |
---|---|
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; |