bookmarks_api.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/file_util_icu.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/time_formatting.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sha1.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string16.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_html_writer.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_utils.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/event_router.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_function_dispatcher.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extensions_quota_service.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/importer_data_types.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/importer_host.h"
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_type.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_select_file_policy.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_notification_types.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/bookmarks.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/user_prefs.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace keys = bookmark_api_constants;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace bookmarks = api::bookmarks;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using bookmarks::BookmarkTreeNode;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef QuotaLimitHeuristic::Bucket Bucket;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef QuotaLimitHeuristic::Config Config;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef QuotaLimitHeuristic::BucketList BucketList;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef ExtensionsQuotaService::TimedLimit TimedLimit;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef ExtensionsQuotaService::SustainedLimit SustainedLimit;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef QuotaLimitHeuristic::BucketMapper BucketMapper;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generates a default path (including a default filename) that will be
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used for pre-populating the "Export Bookmarks" file chooser dialog box.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetDefaultFilepathForBookmarkExport() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time time = base::Time::Now();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Concatenate a date stamp to the filename.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType filename =
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringFUTF8(IDS_EXPORT_BOOKMARKS_DEFAULT_FILENAME,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                base::TimeFormatShortDateNumeric(time));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType filename =
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringFUTF16(IDS_EXPORT_BOOKMARKS_DEFAULT_FILENAME,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 base::TimeFormatShortDateNumeric(time));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::ReplaceIllegalCharactersInPath(&filename, '_');
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath default_path;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathService::Get(chrome::DIR_USER_DOCUMENTS, &default_path);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return default_path.Append(filename);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarksFunction::Run() {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!model->loaded()) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Bookmarks are not ready yet.  We'll wait.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model->AddObserver(this);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddRef();  // Balanced in Loaded().
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = RunImpl();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::NotificationService::current()->Notify(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome::NOTIFICATION_EXTENSION_BOOKMARKS_API_INVOKED,
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        content::Source<const Extension>(GetExtension()),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Details<const BookmarksFunction>(this));
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendResponse(success);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksFunction::GetBookmarkIdAsInt64(const std::string& id_string,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             int64* id) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::StringToInt64(id_string, id))
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_ = keys::kInvalidIdError;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarksFunction::EditBookmarksEnabled() {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* prefs = components::UserPrefs::Get(profile_);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prefs->GetBoolean(prefs::kEditBookmarksEnabled))
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_ = keys::kEditBookmarksDisabled;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksFunction::BookmarkModelChanged() {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksFunction::Loaded(BookmarkModel* model, bool ids_reassigned) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  model->RemoveObserver(this);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Run();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in Run().
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BookmarkEventRouter::BookmarkEventRouter(Profile* profile,
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         BookmarkModel* model)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile),
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      model_(model) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->AddObserver(this);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BookmarkEventRouter::~BookmarkEventRouter() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::DispatchEvent(
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* event_name,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<ListValue> event_args) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extensions::ExtensionSystem::Get(profile_)->event_router()) {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        make_scoped_ptr(new extensions::Event(event_name, event_args.Pass())));
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::Loaded(BookmarkModel* model, bool ids_reassigned) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(erikkay): Perhaps we should send this event down to the extension
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so they know when it's safe to use the API?
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkModelBeingDeleted(BookmarkModel* model) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_ = NULL;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkNodeMoved(BookmarkModel* model,
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const BookmarkNode* old_parent,
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            int old_index,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const BookmarkNode* new_parent,
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            int new_index) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = new_parent->GetChild(new_index);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(new StringValue(base::Int64ToString(node->id())));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* object_args = new DictionaryValue();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetString(keys::kParentIdKey,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::Int64ToString(new_parent->id()));
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetInteger(keys::kIndexKey, new_index);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetString(keys::kOldParentIdKey,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::Int64ToString(old_parent->id()));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetInteger(keys::kOldIndexKey, old_index);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(object_args);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkMoved, args.Pass());
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkNodeAdded(BookmarkModel* model,
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const BookmarkNode* parent,
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            int index) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = parent->GetChild(index);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(new StringValue(base::Int64ToString(node->id())));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<BookmarkTreeNode> tree_node(
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(tree_node->ToValue().release());
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkCreated, args.Pass());
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkNodeRemoved(BookmarkModel* model,
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              const BookmarkNode* parent,
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              int index,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              const BookmarkNode* node) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(new StringValue(base::Int64ToString(node->id())));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* object_args = new DictionaryValue();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetString(keys::kParentIdKey,
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::Int64ToString(parent->id()));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetInteger(keys::kIndexKey, index);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(object_args);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkRemoved, args.Pass());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BookmarkEventRouter::BookmarkAllNodesRemoved(BookmarkModel* model) {
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NOTREACHED();
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(shashishekhar) Currently this notification is only used on Android,
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // which does not support extensions. If Desktop needs to support this, add
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // a new event to the extensions api.
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkNodeChanged(BookmarkModel* model,
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              const BookmarkNode* node) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(new StringValue(base::Int64ToString(node->id())));
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(erikkay) The only three things that BookmarkModel sends this
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notification for are title, url and favicon.  Since we're currently
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ignoring favicon and since the notification doesn't say which one anyway,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for now we only include title and url.  The ideal thing would be to change
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // BookmarkModel to indicate what changed.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* object_args = new DictionaryValue();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_args->SetString(keys::kTitleKey, node->GetTitle());
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url())
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    object_args->SetString(keys::kUrlKey, node->url().spec());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(object_args);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkChanged, args.Pass());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkNodeFaviconChanged(BookmarkModel* model,
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                     const BookmarkNode* node) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(erikkay) anything we should do here?
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::BookmarkNodeChildrenReordered(
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BookmarkModel* model,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BookmarkNode* node) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(new StringValue(base::Int64ToString(node->id())));
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int childCount = node->child_count();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListValue* children = new ListValue();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < childCount; ++i) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* child = node->GetChild(i);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Value* child_id = new StringValue(base::Int64ToString(child->id()));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    children->Append(child_id);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* reorder_info = new DictionaryValue();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reorder_info->Set(keys::kChildIdsKey, children);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Append(reorder_info);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkChildrenReordered, args.Pass());
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::ExtensiveBookmarkChangesBeginning(
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BookmarkModel* model) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkImportBegan, args.Pass());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarkEventRouter::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEvent(keys::kOnBookmarkImportEnded, args.Pass());
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BookmarksAPI::BookmarksAPI(Profile* profile) : profile_(profile) {
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkCreated);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkRemoved);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkChanged);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkMoved);
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkChildrenReordered);
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkImportBegan);
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, keys::kOnBookmarkImportEnded);
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BookmarksAPI::~BookmarksAPI() {
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksAPI::Shutdown() {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static base::LazyInstance<ProfileKeyedAPIFactory<BookmarksAPI> >
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)g_factory = LAZY_INSTANCE_INITIALIZER;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProfileKeyedAPIFactory<BookmarksAPI>* BookmarksAPI::GetFactoryInstance() {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return &g_factory.Get();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksAPI::OnListenerAdded(const EventListenerInfo& details) {
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bookmark_event_router_.reset(new BookmarkEventRouter(profile_,
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BookmarkModelFactory::GetForProfile(profile_)));
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksGetFunction::RunImpl() {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::Get::Params> params(
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::Get::Params::Create(*args_));
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<linked_ptr<BookmarkTreeNode> > nodes;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params->id_or_id_list.as_array) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<std::string>* ids = params->id_or_id_list.as_array.get();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t count = ids->size();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXTENSION_FUNCTION_VALIDATE(count > 0);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < count; ++i) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int64 id;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!GetBookmarkIdAsInt64(ids->at(i), &id))
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BookmarkNode* node = model->GetNodeByID(id);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!node) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        error_ = keys::kNoNodeError;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bookmark_api_helpers::AddNode(node, &nodes, false);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 id;
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!GetBookmarkIdAsInt64(*params->id_or_id_list.as_string, &id))
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = model->GetNodeByID(id);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!node) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = keys::kNoNodeError;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bookmark_api_helpers::AddNode(node, &nodes, false);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::Get::Results::Create(nodes);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksGetChildrenFunction::RunImpl() {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::GetChildren::Params> params(
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::GetChildren::Params::Create(*args_));
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetBookmarkIdAsInt64(params->id, &id))
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<linked_ptr<BookmarkTreeNode> > nodes;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node =
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkModelFactory::GetForProfile(profile())->GetNodeByID(id);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoNodeError;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int child_count = node->child_count();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < child_count; ++i) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* child = node->GetChild(i);
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bookmark_api_helpers::AddNode(child, &nodes, false);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::GetChildren::Results::Create(nodes);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksGetRecentFunction::RunImpl() {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::GetRecent::Params> params(
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::GetRecent::Params::Create(*args_));
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->number_of_items < 1)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_utils::GetMostRecentlyAddedEntries(
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkModelFactory::GetForProfile(profile()),
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params->number_of_items,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &nodes);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<linked_ptr<BookmarkTreeNode> > tree_nodes;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*>::iterator i = nodes.begin();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; i != nodes.end(); ++i) {
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = *i;
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bookmark_api_helpers::AddNode(node, &tree_nodes, false);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::GetRecent::Results::Create(tree_nodes);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksGetTreeFunction::RunImpl() {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<linked_ptr<BookmarkTreeNode> > nodes;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node =
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkModelFactory::GetForProfile(profile())->root_node();
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bookmark_api_helpers::AddNode(node, &nodes, true);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::GetTree::Results::Create(nodes);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksGetSubTreeFunction::RunImpl() {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::GetSubTree::Params> params(
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::GetSubTree::Params::Create(*args_));
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetBookmarkIdAsInt64(params->id, &id))
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node =
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkModelFactory::GetForProfile(profile())->GetNodeByID(id);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoNodeError;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<linked_ptr<BookmarkTreeNode> > nodes;
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bookmark_api_helpers::AddNode(node, &nodes, true);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::GetSubTree::Results::Create(nodes);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksSearchFunction::RunImpl() {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::Search::Params> params(
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::Search::Params::Create(*args_));
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* prefs = components::UserPrefs::Get(profile_);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string lang = prefs->GetString(prefs::kAcceptLanguages);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_utils::GetBookmarksContainingText(
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkModelFactory::GetForProfile(profile()),
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UTF8ToUTF16(params->query),
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::numeric_limits<int>::max(),
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lang,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &nodes);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<linked_ptr<BookmarkTreeNode> > tree_nodes;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<const BookmarkNode*>::iterator node_iter = nodes.begin();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       node_iter != nodes.end(); ++node_iter) {
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bookmark_api_helpers::AddNode(*node_iter, &tree_nodes, false);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::Search::Results::Create(tree_nodes);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksRemoveFunction::ExtractIds(const ListValue* args,
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         std::list<int64>* ids,
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         bool* invalid_id) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id_string;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!args->GetString(0, &id_string))
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::StringToInt64(id_string, &id))
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ids->push_back(id);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *invalid_id = true;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksRemoveFunction::RunImpl() {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EditBookmarksEnabled())
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::Remove::Params> params(
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::Remove::Params::Create(*args_));
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt64(params->id, &id)) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kInvalidIdError;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool recursive = false;
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (name() == BookmarksRemoveTreeFunction::function_name())
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recursive = true;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!bookmark_api_helpers::RemoveNode(model, id, recursive, &error_))
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksCreateFunction::RunImpl() {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EditBookmarksEnabled())
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::Create::Params> params(
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::Create::Params::Create(*args_));
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 parentId;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params->bookmark.parent_id.get()) {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Optional, default to "other bookmarks".
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parentId = model->other_node()->id();
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetBookmarkIdAsInt64(*params->bookmark.parent_id, &parentId))
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = model->GetNodeByID(parentId);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent) {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoParentError;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent->is_root()) {  // Can't create children of the root.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kModifySpecialError;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params->bookmark.index.get()) {  // Optional (defaults to end).
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = parent->child_count();
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = *params->bookmark.index;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index > parent->child_count() || index < 0) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = keys::kInvalidIndexError;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 title;  // Optional.
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->bookmark.title.get())
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    title = UTF8ToUTF16(*params->bookmark.title.get());
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string url_string;  // Optional.
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->bookmark.url.get())
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_string = *params->bookmark.url.get();
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url(url_string);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url_string.empty() && !url.is_valid()) {
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kInvalidUrlError;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_string.length())
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node = model->AddURL(parent, index, title, url);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node = model->AddFolder(parent, index, title);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoNodeError;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<BookmarkTreeNode> ret(
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::Create::Results::Create(*ret);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksMoveFunction::ExtractIds(const ListValue* args,
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       std::list<int64>* ids,
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       bool* invalid_id) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For now, Move accepts ID parameters in the same way as an Update.
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return BookmarksUpdateFunction::ExtractIds(args, ids, invalid_id);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksMoveFunction::RunImpl() {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EditBookmarksEnabled())
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::Move::Params> params(
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::Move::Params::Create(*args_));
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt64(params->id, &id)) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kInvalidIdError;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = model->GetNodeByID(id);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoNodeError;
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model->is_permanent_node(node)) {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kModifySpecialError;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = NULL;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params->destination.parent_id.get()) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Optional, defaults to current parent.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent = node->parent();
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 parentId;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetBookmarkIdAsInt64(*params->destination.parent_id, &parentId))
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent = model->GetNodeByID(parentId);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoParentError;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(erikkay) return an error message.
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent == model->root_node()) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kModifySpecialError;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->destination.index.get()) {  // Optional (defaults to end).
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = *params->destination.index;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index > parent->child_count() || index < 0) {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = keys::kInvalidIndexError;
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = parent->child_count();
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model->Move(node, parent, index);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<BookmarkTreeNode> tree_node(
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::Move::Results::Create(*tree_node);
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksUpdateFunction::ExtractIds(const ListValue* args,
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         std::list<int64>* ids,
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         bool* invalid_id) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For now, Update accepts ID parameters in the same way as an Remove.
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return BookmarksRemoveFunction::ExtractIds(args, ids, invalid_id);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksUpdateFunction::RunImpl() {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EditBookmarksEnabled())
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<bookmarks::Update::Params> params(
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::Update::Params::Create(*args_));
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id;
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt64(params->id, &id)) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kInvalidIdError;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Optional but we need to distinguish non present from an empty title.
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 title;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_title = false;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->changes.title.get()) {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    title = UTF8ToUTF16(*params->changes.title);
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    has_title = true;
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Optional.
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string url_string;
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->changes.url.get())
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_string = *params->changes.url;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url(url_string);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url_string.empty() && !url.is_valid()) {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kInvalidUrlError;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = model->GetNodeByID(id);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kNoNodeError;
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model->is_permanent_node(node)) {
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = keys::kModifySpecialError;
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_title)
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model->SetTitle(node, title);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url.is_empty())
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model->SetURL(node, url);
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<BookmarkTreeNode> tree_node(
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = bookmarks::Update::Results::Create(*tree_node);
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mapper superclass for BookmarkFunctions.
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <typename BucketIdType>
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BookmarkBucketMapper : public BucketMapper {
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~BookmarkBucketMapper() { STLDeleteValues(&buckets_); }
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Bucket* GetBucket(const BucketIdType& id) {
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Bucket* b = buckets_[id];
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (b == NULL) {
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      b = new Bucket();
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buckets_[id] = b;
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return b;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<BucketIdType, Bucket*> buckets_;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mapper for 'bookmarks.create'.  Maps "same input to bookmarks.create" to a
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// unique bucket.
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CreateBookmarkBucketMapper : public BookmarkBucketMapper<std::string> {
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CreateBookmarkBucketMapper(Profile* profile) : profile_(profile) {}
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(tim): This should share code with BookmarksCreateFunction::RunImpl,
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but I can't figure out a good way to do that with all the macros.
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void GetBucketsForArgs(const ListValue* args,
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 BucketList* buckets) OVERRIDE {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DictionaryValue* json;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!args->GetDictionary(0, &json))
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string parent_id;
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (json->HasKey(keys::kParentIdKey)) {
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!json->GetString(keys::kParentIdKey, &parent_id))
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile_);
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 parent_id_int64;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::StringToInt64(parent_id, &parent_id_int64);
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* parent = model->GetNodeByID(parent_id_int64);
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!parent)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string bucket_id = UTF16ToUTF8(parent->GetTitle());
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string title;
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json->GetString(keys::kTitleKey, &title);
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url_string;
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json->GetString(keys::kUrlKey, &url_string);
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bucket_id += title;
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bucket_id += url_string;
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // 20 bytes (SHA1 hash length) is very likely less than most of the
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |bucket_id| strings we construct here, so we hash it to save space.
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buckets->push_back(GetBucket(base::SHA1HashString(bucket_id)));
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile_;
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mapper for 'bookmarks.remove'.
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RemoveBookmarksBucketMapper : public BookmarkBucketMapper<std::string> {
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit RemoveBookmarksBucketMapper(Profile* profile) : profile_(profile) {}
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void GetBucketsForArgs(const ListValue* args,
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 BucketList* buckets) OVERRIDE {
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typedef std::list<int64> IdList;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IdList ids;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool invalid_id = false;
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!BookmarksRemoveFunction::ExtractIds(args, &ids, &invalid_id) ||
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        invalid_id) {
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (IdList::iterator it = ids.begin(); it != ids.end(); ++it) {
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile_);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BookmarkNode* node = model->GetNodeByID(*it);
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!node || node->is_root())
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string bucket_id;
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bucket_id += UTF16ToUTF8(node->parent()->GetTitle());
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bucket_id += UTF16ToUTF8(node->GetTitle());
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bucket_id += node->url().spec();
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buckets->push_back(GetBucket(base::SHA1HashString(bucket_id)));
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile_;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mapper for any bookmark function accepting bookmark IDs as parameters, where
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a distinct ID corresponds to a single item in terms of quota limiting.  This
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is inappropriate for bookmarks.remove, for example, since repeated removals
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the same item will actually have a different ID each time.
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class FunctionType>
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BookmarkIdMapper : public BookmarkBucketMapper<int64> {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::list<int64> IdList;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void GetBucketsForArgs(const ListValue* args, BucketList* buckets) {
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IdList ids;
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool invalid_id = false;
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!FunctionType::ExtractIds(args, &ids, &invalid_id) || invalid_id)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (IdList::iterator it = ids.begin(); it != ids.end(); ++it)
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buckets->push_back(GetBucket(*it));
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Builds heuristics for all BookmarkFunctions using specialized BucketMappers.
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BookmarksQuotaLimitFactory {
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For id-based bookmark functions.
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class FunctionType>
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void Build(QuotaLimitHeuristics* heuristics) {
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BuildWithMappers(heuristics, new BookmarkIdMapper<FunctionType>(),
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 new BookmarkIdMapper<FunctionType>());
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For bookmarks.create.
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void BuildForCreate(QuotaLimitHeuristics* heuristics,
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             Profile* profile) {
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BuildWithMappers(heuristics, new CreateBookmarkBucketMapper(profile),
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 new CreateBookmarkBucketMapper(profile));
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For bookmarks.remove.
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void BuildForRemove(QuotaLimitHeuristics* heuristics,
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             Profile* profile) {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BuildWithMappers(heuristics, new RemoveBookmarksBucketMapper(profile),
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 new RemoveBookmarksBucketMapper(profile));
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void BuildWithMappers(QuotaLimitHeuristics* heuristics,
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BucketMapper* short_mapper, BucketMapper* long_mapper) {
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Config kSustainedLimitConfig = {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // See bookmarks.json for current value.
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE,
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TimeDelta::FromMinutes(1)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    heuristics->push_back(new SustainedLimit(
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromMinutes(10),
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kSustainedLimitConfig,
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        short_mapper,
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE"));
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Config kTimedLimitConfig = {
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // See bookmarks.json for current value.
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks::MAX_WRITE_OPERATIONS_PER_HOUR,
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TimeDelta::FromHours(1)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    heuristics->push_back(new TimedLimit(
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kTimedLimitConfig,
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long_mapper,
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "MAX_WRITE_OPERATIONS_PER_HOUR"));
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_IMPLICIT_CONSTRUCTORS(BookmarksQuotaLimitFactory);
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// And finally, building the individual heuristics for each function.
8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksRemoveFunction::GetQuotaLimitHeuristics(
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    QuotaLimitHeuristics* heuristics) const {
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarksQuotaLimitFactory::BuildForRemove(heuristics, profile());
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksMoveFunction::GetQuotaLimitHeuristics(
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    QuotaLimitHeuristics* heuristics) const {
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BookmarksQuotaLimitFactory::Build<BookmarksMoveFunction>(heuristics);
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksUpdateFunction::GetQuotaLimitHeuristics(
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    QuotaLimitHeuristics* heuristics) const {
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BookmarksQuotaLimitFactory::Build<BookmarksUpdateFunction>(heuristics);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksCreateFunction::GetQuotaLimitHeuristics(
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    QuotaLimitHeuristics* heuristics) const {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarksQuotaLimitFactory::BuildForCreate(heuristics, profile());
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarksIOFunction::BookmarksIOFunction() {}
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarksIOFunction::~BookmarksIOFunction() {
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There may be pending file dialogs, we need to tell them that we've gone
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // away so they don't try and call back to us.
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select_file_dialog_.get())
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    select_file_dialog_->ListenerDestroyed();
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarksIOFunction::SelectFile(ui::SelectFileDialog::Type type) {
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetDefaultFilepathForBookmarkExport() might have to touch the filesystem
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (stat or access, for example), so this requires a thread with IO allowed.
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BookmarksIOFunction::SelectFile, this, type));
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pre-populating the filename field in case this is a SELECT_SAVEAS_FILE
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dialog. If not, there is no filename field in the dialog box.
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath default_path;
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == ui::SelectFileDialog::SELECT_SAVEAS_FILE)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_path = GetDefaultFilepathForBookmarkExport();
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(type == ui::SelectFileDialog::SELECT_OPEN_FILE);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After getting the |default_path|, ask the UI to display the file dialog.
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BookmarksIOFunction::ShowSelectFileDialog, this,
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 type, default_path));
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksIOFunction::ShowSelectFileDialog(
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::SelectFileDialog::Type type,
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& default_path) {
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dispatcher())
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;  // Extension was unloaded.
9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Balanced in one of the three callbacks of SelectFileDialog:
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // either FileSelectionCanceled, MultiFilesSelected, or FileSelected
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents = dispatcher()->delegate()->
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAssociatedWebContents();
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  select_file_dialog_ = ui::SelectFileDialog::Create(
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, new ChromeSelectFilePolicy(web_contents));
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SelectFileDialog::FileTypeInfo file_type_info;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_type_info.extensions.resize(1);
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html"));
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(kinaba): http://crbug.com/140425. Turn file_type_info.support_drive
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // on for saving once Google Drive client on ChromeOS supports it.
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == ui::SelectFileDialog::SELECT_OPEN_FILE)
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    file_type_info.support_drive = true;
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |web_contents| can be NULL (for background pages), which is fine. In such
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a case if file-selection dialogs are forbidden by policy, we will not
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // show an InfoBar, which is better than letting one appear out of the blue.
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  select_file_dialog_->SelectFile(type,
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  string16(),
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  default_path,
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  &file_type_info,
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  0,
950c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  base::FilePath::StringType(),
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  NULL,
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  NULL);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarksIOFunction::FileSelectionCanceled(void* params) {
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in BookmarksIOFunction::SelectFile()
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarksIOFunction::MultiFilesSelected(
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<base::FilePath>& files, void* params) {
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in BookmarsIOFunction::SelectFile()
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Should not be able to select multiple files";
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksImportFunction::RunImpl() {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EditBookmarksEnabled())
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE);
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksImportFunction::FileSelected(const base::FilePath& path,
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int index,
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           void* params) {
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Android does not have support for the standard importers.
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jgreenwald): remove ifdef once extensions are no longer built on
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Android.
979c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Deletes itself.
980c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ImporterHost* importer_host = new ImporterHost;
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  importer::SourceProfile source_profile;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE;
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source_profile.source_path = path;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  importer_host->StartImportSettings(source_profile,
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     profile(),
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     importer::FAVORITES,
987c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     new ProfileWriter(profile()));
988c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
989c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  importer::LogImporterUseToMetrics("BookmarksAPI",
990c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    importer::TYPE_BOOKMARKS_FILE);
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in BookmarksIOFunction::SelectFile()
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarksExportFunction::RunImpl() {
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE);
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BookmarksExportFunction::FileSelected(const base::FilePath& path,
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int index,
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           void* params) {
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Android does not have support for the standard exporter.
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jgreenwald): remove ifdef once extensions are no longer built on
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Android.
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_html_writer::WriteBookmarks(profile(), path, NULL);
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in BookmarksIOFunction::SelectFile()
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
1013