nsresult
nsSafariProfileMigrator::CopyHistoryBatched(bool aReplace)
{
  nsCOMPtr<nsIProperties> fileLocator(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
  nsCOMPtr<nsILocalFile> safariHistoryFile;
  fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile),
                   getter_AddRefs(safariHistoryFile));
  safariHistoryFile->Append(NS_LITERAL_STRING("Safari"));
  safariHistoryFile->Append(SAFARI_HISTORY_FILE_NAME);

  CFDictionaryRef safariHistory =
    static_cast<CFDictionaryRef>(CopyPListFromFile(safariHistoryFile));
  if (!safariHistory)
    return NS_OK;

  if (!::CFDictionaryContainsKey(safariHistory, CFSTR("WebHistoryDates"))) {
    ::CFRelease(safariHistory);
    return NS_OK;
  }

  nsCOMPtr<nsIBrowserHistory> history(do_GetService(NS_GLOBALHISTORY2_CONTRACTID));

  CFArrayRef children = (CFArrayRef)
                ::CFDictionaryGetValue(safariHistory, CFSTR("WebHistoryDates"));
  if (children) {
    CFIndex count = ::CFArrayGetCount(children);
    for (PRInt32 i = 0; i < count; ++i) {
      CFDictionaryRef entry = (CFDictionaryRef)::CFArrayGetValueAtIndex(children, i);

      CFStringRef lastVisitedDate = (CFStringRef)
                        ::CFDictionaryGetValue(entry, CFSTR("lastVisitedDate"));
      nsAutoString url, title;
      if (GetDictionaryStringValue(entry, CFSTR(""), url) &&
          GetDictionaryStringValue(entry, CFSTR("title"), title) &&
          lastVisitedDate) {

        double lvd = ::CFStringGetDoubleValue(lastVisitedDate) + SAFARI_DATE_OFFSET;
        PRTime lastVisitTime;
        PRInt64 temp, million;
        LL_D2L(temp, lvd);
        LL_I2L(million, PR_USEC_PER_SEC);
        LL_MUL(lastVisitTime, temp, million);

        nsCOMPtr<nsIURI> uri;
        NS_NewURI(getter_AddRefs(uri), url);
        if (uri)
          history->AddPageWithDetails(uri, title.get(), lastVisitTime);
      }
    }
  }

  ::CFRelease(safariHistory);

  return NS_OK;
}
nsresult
nsSafariProfileMigrator::GetSafariUserStyleSheet(nsILocalFile** aResult)
{
  *aResult = nsnull;

  CFDictionaryRef safariPrefs = CopySafariPrefs();
  if (!safariPrefs)
    return NS_ERROR_FAILURE;

  nsresult rv = NS_ERROR_FAILURE;
  // Check whether or not a user style sheet has been specified
  if (::CFDictionaryContainsKey
        (safariPrefs, CFSTR("WebKitUserStyleSheetEnabledPreferenceKey")) &&
      ::CFDictionaryContainsKey
        (safariPrefs, CFSTR("WebKitUserStyleSheetLocationPreferenceKey"))) {
    CFBooleanRef hasSheet = (CFBooleanRef)::CFDictionaryGetValue(safariPrefs,
                             CFSTR("WebKitUserStyleSheetEnabledPreferenceKey"));
    if (hasSheet == kCFBooleanTrue) {
      nsAutoString path;
      // Get its path
      if (GetDictionaryStringValue(safariPrefs,
                                   CFSTR("WebKitUserStyleSheetLocation" \
                                   "PreferenceKey"), path)) {
        nsCOMPtr<nsILocalFile> file;
        rv = NS_NewLocalFile(path, false, getter_AddRefs(file));
        if (NS_SUCCEEDED(rv)) {
          bool exists = false;
          file->Exists(&exists);
          if (exists) {
            NS_ADDREF(*aResult = file);
            rv = NS_OK;
          }
          else
            rv = NS_ERROR_FILE_NOT_FOUND;
        }
      }
    }
  }
  ::CFRelease(safariPrefs);

  return rv;
}
nsresult
nsSafariProfileMigrator::CopyPreferences(bool aReplace)
{
  nsCOMPtr<nsIPrefBranch> branch(do_GetService(NS_PREFSERVICE_CONTRACTID));

  CFDictionaryRef safariPrefs = CopySafariPrefs();
  if (!safariPrefs)
    return NS_ERROR_FAILURE;

  // Traverse the standard transforms
  PrefTransform* transform;
  PrefTransform* end = gTransforms +
                       sizeof(gTransforms) / sizeof(PrefTransform);

  for (transform = gTransforms; transform < end; ++transform) {
    Boolean hasValue = ::CFDictionaryContainsKey(safariPrefs, transform->keyName);
    if (!hasValue)
      continue;

    transform->prefHasValue = false;
    switch (transform->type) {
    case _SPM(STRING): {
        CFStringRef stringValue = (CFStringRef)
                                  ::CFDictionaryGetValue(safariPrefs,
                                                         transform->keyName);
        char* value = GetNullTerminatedString(stringValue);
        if (value) {
          transform->stringValue = value;
          transform->prefHasValue = true;
        }
      }
      break;
    case _SPM(INT): {
        CFNumberRef intValue = (CFNumberRef)
                               ::CFDictionaryGetValue(safariPrefs,
                                                      transform->keyName);
        PRInt32 value = 0;
        if (::CFNumberGetValue(intValue, kCFNumberSInt32Type, &value)) {
          transform->intValue = value;
          transform->prefHasValue = true;
        }
      }
      break;
    case _SPM(BOOL): {
        CFBooleanRef boolValue = (CFBooleanRef)
                                 ::CFDictionaryGetValue(safariPrefs,
                                                        transform->keyName);
        transform->boolValue = boolValue == kCFBooleanTrue;
        transform->prefHasValue = true;
      }
      break;
    default:
      break;
    }

    if (transform->prefHasValue)
      transform->prefSetterFunc(transform, branch);

    if (transform->type == _SPM(STRING))
      FreeNullTerminatedString(transform->stringValue);
  }

  ::CFRelease(safariPrefs);

  // Safari stores the Cookie "Accept/Don't Accept/Don't Accept Foreign" cookie
  // setting in a separate WebFoundation preferences PList.
  nsCOMPtr<nsIProperties> fileLocator(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
  nsCOMPtr<nsILocalFile> safariWebFoundationPrefsFile;
  fileLocator->Get(NS_OSX_USER_PREFERENCES_DIR, NS_GET_IID(nsILocalFile),
                   getter_AddRefs(safariWebFoundationPrefsFile));
  safariWebFoundationPrefsFile->Append(SAFARI_COOKIE_BEHAVIOR_FILE_NAME);

  CFDictionaryRef safariWebFoundationPrefs =
    static_cast<CFDictionaryRef>(CopyPListFromFile(safariWebFoundationPrefsFile));
  if (safariWebFoundationPrefs) {
    // Mapping of Safari preference values to Firefox preference values:
    //
    // Setting                    Safari          Firefox
    // Always Accept              always          0
    // Accept from Originating    current page    1
    // Never Accept               never           2
    nsAutoString acceptCookies;
    if (GetDictionaryStringValue(safariWebFoundationPrefs,
                                 CFSTR("NSHTTPAcceptCookies"), acceptCookies)) {
      PRInt32 cookieValue = 0;
      if (acceptCookies.EqualsLiteral("never"))
        cookieValue = 2;
      else if (acceptCookies.EqualsLiteral("current page"))
        cookieValue = 1;

      branch->SetIntPref("network.cookie.cookieBehavior", cookieValue);
    }

    ::CFRelease(safariWebFoundationPrefs);
  }

  return NS_OK;
}
nsresult
nsSafariProfileMigrator::ParseBookmarksFolder(CFArrayRef aChildren,
                                              PRInt64 aParentFolder,
                                              nsINavBookmarksService * aBookmarksService,
                                              bool aIsAtRootLevel)
{
  nsresult rv = NS_OK;

  CFIndex count = ::CFArrayGetCount(aChildren);
  for (PRInt32 i = 0; i < count; ++i) {
    CFDictionaryRef entry = (CFDictionaryRef)::CFArrayGetValueAtIndex(aChildren, i);

    nsAutoString type;
    if (!GetDictionaryStringValue(entry, CFSTR("WebBookmarkType"), type))
      continue;

    if (!type.EqualsLiteral("WebBookmarkTypeList") &&
        !type.EqualsLiteral("WebBookmarkTypeLeaf"))
      continue;

    if (::CFDictionaryContainsKey(entry, CFSTR("Children")) &&
        type.EqualsLiteral("WebBookmarkTypeList")) {
      nsAutoString title;
      if (!GetDictionaryStringValue(entry, CFSTR("Title"), title))
        continue;

      CFArrayRef children = (CFArrayRef)::CFDictionaryGetValue(entry,
                                                               CFSTR("Children"));

      // Look for the BookmarksBar Bookmarks and add them into the appropriate
      // Personal Toolbar Root
      if (title.EqualsLiteral("BookmarksBar") && aIsAtRootLevel) {
        PRInt64 toolbarFolder;
        aBookmarksService->GetToolbarFolder(&toolbarFolder);

        rv |= ParseBookmarksFolder(children,
                                   toolbarFolder,
                                   aBookmarksService,
                                   false);
      }
      // Look for the BookmarksMenu Bookmarks and flatten them into the top level
      else if (title.EqualsLiteral("BookmarksMenu") && aIsAtRootLevel) {
        rv |= ParseBookmarksFolder(children,
                                   aParentFolder,
                                   aBookmarksService,
                                   true);
      }
      else {
        // Encountered a Folder, so create one in our Bookmarks DataSource and then
        // parse the contents of the Safari one into it...
        PRInt64 folder;
        rv |= aBookmarksService->CreateFolder(aParentFolder, NS_ConvertUTF16toUTF8(title),
                                              nsINavBookmarksService::DEFAULT_INDEX,
                                              &folder);
        rv |= ParseBookmarksFolder(children,
                                   folder,
                                   aBookmarksService,
                                   false);
      }
    }
    else if (type.EqualsLiteral("WebBookmarkTypeLeaf")) {
      // Encountered a Bookmark, so add it to the current folder...
      CFDictionaryRef URIDictionary = (CFDictionaryRef)
                      ::CFDictionaryGetValue(entry, CFSTR("URIDictionary"));
      nsAutoString title;
      nsCAutoString url;
      if (GetDictionaryStringValue(URIDictionary, CFSTR("title"), title) &&
          GetDictionaryCStringValue(entry, CFSTR("URLString"), url, kCFStringEncodingUTF8)) {
        nsCOMPtr<nsIURI> uri;
        rv = NS_NewURI(getter_AddRefs(uri), url);
        if (NS_SUCCEEDED(rv)) {
          PRInt64 id;
          rv = aBookmarksService->InsertBookmark(aParentFolder, uri,
                                                 nsINavBookmarksService::DEFAULT_INDEX,
                                                 NS_ConvertUTF16toUTF8(title), &id);
        }
      }
    }
  }
  return rv;
}
nsresult
nsSafariProfileMigrator::ParseBookmarksFolder(CFArrayRef aChildren,
#ifdef MOZ_PLACES
        PRInt64 aParentFolder,
        nsINavBookmarksService * aBookmarksService,
#else
        nsIRDFResource* aParentResource,
        nsIBookmarksService* aBookmarksService,
#endif
        PRBool aIsAtRootLevel)
{
    nsresult rv;

    CFIndex count = ::CFArrayGetCount(aChildren);
    for (PRInt32 i = 0; i < count; ++i) {
        CFDictionaryRef entry = (CFDictionaryRef)::CFArrayGetValueAtIndex(aChildren, i);

        nsAutoString type;
        if (!GetDictionaryStringValue(entry, CFSTR("WebBookmarkType"), type))
            continue;

        if (!type.EqualsLiteral("WebBookmarkTypeList") &&
                !type.EqualsLiteral("WebBookmarkTypeLeaf"))
            continue;

        if (::CFDictionaryContainsKey(entry, CFSTR("Children")) &&
                type.EqualsLiteral("WebBookmarkTypeList")) {
            nsAutoString title;
            if (!GetDictionaryStringValue(entry, CFSTR("Title"), title))
                continue;

            CFArrayRef children = (CFArrayRef)::CFDictionaryGetValue(entry,
                                  CFSTR("Children"));

            // Look for the BookmarksBar Bookmarks and add them into the appropriate
            // Personal Toolbar Root
            if (title.EqualsLiteral("BookmarksBar") && aIsAtRootLevel) {
#ifdef MOZ_PLACES
                PRInt64 toolbarFolder;
                aBookmarksService->GetToolbarRoot(&toolbarFolder);
#else
                nsCOMPtr<nsIRDFResource> toolbarFolder;
                aBookmarksService->GetBookmarksToolbarFolder(getter_AddRefs(toolbarFolder));
#endif

                rv |= ParseBookmarksFolder(children,
                                           toolbarFolder,
                                           aBookmarksService,
                                           PR_FALSE);
            }
            // Look for the BookmarksMenu Bookmarks and flatten them into the top level
            else if (title.EqualsLiteral("BookmarksMenu") && aIsAtRootLevel) {
                rv |= ParseBookmarksFolder(children,
#ifdef MOZ_PLACES
                                           aParentFolder,
#else
                                           aParentResource,
#endif
                                           aBookmarksService,
                                           PR_TRUE);
            }
            else {
                // Encountered a Folder, so create one in our Bookmarks DataSource and then
                // parse the contents of the Safari one into it...
#ifdef MOZ_PLACES
                PRInt64 folder;
                rv |= aBookmarksService->CreateFolder(aParentFolder,
                                                      title, -1, &folder);
#else
                nsCOMPtr<nsIRDFResource> folder;
                rv |= aBookmarksService->CreateFolderInContainer(title.get(),
                        aParentResource,
                        -1,
                        getter_AddRefs(folder));
#endif
                rv |= ParseBookmarksFolder(children,
                                           folder,
                                           aBookmarksService,
                                           PR_FALSE);
            }
        }
        else if (type.EqualsLiteral("WebBookmarkTypeLeaf")) {
            // Encountered a Bookmark, so add it to the current folder...
            CFDictionaryRef URIDictionary = (CFDictionaryRef)
                                            ::CFDictionaryGetValue(entry, CFSTR("URIDictionary"));
            nsAutoString title, url;
            if (GetDictionaryStringValue(URIDictionary, CFSTR("title"), title) &&
                    GetDictionaryStringValue(entry, CFSTR("URLString"), url)) {
#ifdef MOZ_PLACES
                nsCOMPtr<nsIURI> uri;
                rv |= NS_NewURI(getter_AddRefs(uri), url);
                rv |= aBookmarksService->InsertItem(aParentFolder, uri, -1);
                rv |= aBookmarksService->SetItemTitle(uri, title);
#else
                nsCOMPtr<nsIRDFResource> bookmark;
                rv |= aBookmarksService->CreateBookmarkInContainer(title.get(),
                        url.get(),
                        nsnull,
                        nsnull,
                        nsnull,
                        nsnull,
                        aParentResource,
                        -1,
                        getter_AddRefs(bookmark));
#endif
            }
        }
    }
    return rv;
}