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;