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/context_menus/context_menus_api.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/menu_manager.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/context_menus.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/background_info.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/url_pattern_set.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::ErrorUtils;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kGeneratedIdKey[] = "generatedId";
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCannotFindItemError[] = "Cannot find menu item with id *";
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kOnclickDisallowedError[] = "Extensions using event pages cannot "
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "pass an onclick parameter to chrome.contextMenus.create. Instead, use "
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "the chrome.contextMenus.onClicked event.";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCheckedError[] =
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Only items with type \"radio\" or \"checkbox\" can be checked";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDuplicateIDError[] =
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Cannot create item with duplicate id *";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kIdRequiredError[] = "Extensions using event pages must pass an "
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "id parameter to chrome.contextMenus.create";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParentsMustBeNormalError[] =
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Parent items must have type \"normal\"";
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTitleNeededError[] =
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "All menu items except for separators must have a title";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLauncherNotAllowedError[] =
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Only packaged apps are allowed to use 'launcher' context";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetIDString(const extensions::MenuItem::Id& id) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id.uid == 0)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return id.string_uid;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::IntToString(id.uid);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename PropertyWithEnumT>
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extensions::MenuItem::ContextList GetContexts(
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PropertyWithEnumT& property) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::MenuItem::ContextList contexts;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < property.contexts->size(); ++i) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (property.contexts->at(i)) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_ALL:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::ALL);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_PAGE:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::PAGE);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_SELECTION:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::SELECTION);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_LINK:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::LINK);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_EDITABLE:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::EDITABLE);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_IMAGE:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::IMAGE);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_VIDEO:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::VIDEO);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_AUDIO:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::AUDIO);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_FRAME:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::FRAME);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_LAUNCHER:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contexts.Add(extensions::MenuItem::LAUNCHER);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case PropertyWithEnumT::CONTEXTS_TYPE_NONE:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contexts;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename PropertyWithEnumT>
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)extensions::MenuItem::Type GetType(const PropertyWithEnumT& property,
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   extensions::MenuItem::Type default_type) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (property.type) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PropertyWithEnumT::TYPE_NONE:
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return default_type;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PropertyWithEnumT::TYPE_NORMAL:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extensions::MenuItem::NORMAL;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PropertyWithEnumT::TYPE_CHECKBOX:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extensions::MenuItem::CHECKBOX;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PropertyWithEnumT::TYPE_RADIO:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extensions::MenuItem::RADIO;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PropertyWithEnumT::TYPE_SEPARATOR:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extensions::MenuItem::SEPARATOR;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extensions::MenuItem::NORMAL;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename PropertyWithEnumT>
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<extensions::MenuItem::Id> GetParentId(
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PropertyWithEnumT& property,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_off_the_record,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string extension_id) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!property.parent_id)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<extensions::MenuItem::Id>();
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<extensions::MenuItem::Id> parent_id(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new extensions::MenuItem::Id(is_off_the_record, extension_id));
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (property.parent_id->as_integer)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    parent_id->uid = *property.parent_id->as_integer;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (property.parent_id->as_string)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    parent_id->string_uid = *property.parent_id->as_string;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parent_id.Pass();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extensions::MenuItem* GetParent(extensions::MenuItem::Id parent_id,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const extensions::MenuManager* menu_manager,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                std::string* error) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::MenuItem* parent = menu_manager->GetItemById(parent_id);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent) {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessage(
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kCannotFindItemError, GetIDString(parent_id));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent->type() != extensions::MenuItem::NORMAL) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = kParentsMustBeNormalError;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parent;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace Create = api::context_menus::Create;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace Remove = api::context_menus::Remove;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace Update = api::context_menus::Update;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ContextMenusCreateFunction::RunImpl() {
1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  MenuItem::Id id(GetProfile()->IsOffTheRecord(), extension_id());
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Create::Params> params(Create::Params::Create(*args_));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->create_properties.id.get()) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    id.string_uid = *params->create_properties.id;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (BackgroundInfo::HasLazyBackgroundPage(GetExtension())) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kIdRequiredError;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The Generated Id is added by context_menus_custom_bindings.js.
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::DictionaryValue* properties = NULL;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &properties));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kGeneratedIdKey,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       &id.uid));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string title;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->create_properties.title.get())
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    title = *params->create_properties.title;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MenuManager* menu_manager = MenuManager::Get(GetProfile());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (menu_manager->GetItemById(id)) {
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_ = ErrorUtils::FormatErrorMessage(kDuplicateIDError,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     GetIDString(id));
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (BackgroundInfo::HasLazyBackgroundPage(GetExtension()) &&
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params->create_properties.onclick.get()) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = kOnclickDisallowedError;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItem::ContextList contexts;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->create_properties.contexts.get())
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contexts = GetContexts(params->create_properties);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contexts.Add(MenuItem::PAGE);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contexts.Contains(MenuItem::LAUNCHER) &&
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !GetExtension()->is_platform_app()) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = kLauncherNotAllowedError;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MenuItem::Type type = GetType(params->create_properties, MenuItem::NORMAL);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (title.empty() && type != MenuItem::SEPARATOR) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = kTitleNeededError;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool checked = false;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->create_properties.checked.get())
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    checked = *params->create_properties.checked;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enabled = true;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->create_properties.enabled.get())
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enabled = *params->create_properties.enabled;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MenuItem> item(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new MenuItem(id, title, checked, enabled, type, contexts));
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item->PopulateURLPatterns(
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params->create_properties.document_url_patterns.get(),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params->create_properties.target_url_patterns.get(),
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &error_)) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = true;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MenuItem::Id> parent_id(GetParentId(params->create_properties,
2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                 GetProfile()->IsOffTheRecord(),
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 extension_id()));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent_id.get()) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItem* parent = GetParent(*parent_id, menu_manager, &error_);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!parent)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success = menu_manager->AddChildItem(parent->id(), item.release());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success = menu_manager->AddContextItem(GetExtension(), item.release());
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_manager->WriteToStorage(GetExtension());
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ContextMenusUpdateFunction::RunImpl() {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool radio_item_updated = false;
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  MenuItem::Id item_id(GetProfile()->IsOffTheRecord(), extension_id());
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Update::Params> params(Update::Params::Create(*args_));
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params->id.as_string)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item_id.string_uid = *params->id.as_string;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (params->id.as_integer)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item_id.uid = *params->id.as_integer;
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MenuManager* manager = MenuManager::Get(GetProfile());
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItem* item = manager->GetItemById(item_id);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item || item->extension_id() != extension_id()) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_ = ErrorUtils::FormatErrorMessage(
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kCannotFindItemError, GetIDString(item_id));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Type.
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MenuItem::Type type = GetType(params->update_properties, item->type());
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type != item->type()) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type == MenuItem::RADIO || item->type() == MenuItem::RADIO)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      radio_item_updated = true;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    item->set_type(type);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Title.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->update_properties.title.get()) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string title(*params->update_properties.title);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (title.empty() && item->type() != MenuItem::SEPARATOR) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kTitleNeededError;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    item->set_title(title);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Checked state.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->update_properties.checked.get()) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool checked = *params->update_properties.checked;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (checked &&
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        item->type() != MenuItem::CHECKBOX &&
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        item->type() != MenuItem::RADIO) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kCheckedError;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (checked != item->checked()) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!item->SetChecked(checked)) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        error_ = kCheckedError;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      radio_item_updated = true;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enabled.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->update_properties.enabled.get())
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    item->set_enabled(*params->update_properties.enabled);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Contexts.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItem::ContextList contexts;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params->update_properties.contexts.get()) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contexts = GetContexts(params->update_properties);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (contexts.Contains(MenuItem::LAUNCHER) &&
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !GetExtension()->is_platform_app()) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kLauncherNotAllowedError;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (contexts != item->contexts())
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item->set_contexts(contexts);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parent id.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItem* parent = NULL;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MenuItem::Id> parent_id(GetParentId(params->update_properties,
3291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                 GetProfile()->IsOffTheRecord(),
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 extension_id()));
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent_id.get()) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItem* parent = GetParent(*parent_id, manager, &error_);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!parent || !manager->ChangeParent(item->id(), &parent->id()))
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URL Patterns.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item->PopulateURLPatterns(
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params->update_properties.document_url_patterns.get(),
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params->update_properties.target_url_patterns.get(), &error_)) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is no need to call ItemUpdated if ChangeParent is called because
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all sanitation is taken care of in ChangeParent.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent && radio_item_updated && !manager->ItemUpdated(item->id()))
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manager->WriteToStorage(GetExtension());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ContextMenusRemoveFunction::RunImpl() {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Remove::Params> params(Remove::Params::Create(*args_));
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MenuManager* manager = MenuManager::Get(GetProfile());
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  MenuItem::Id id(GetProfile()->IsOffTheRecord(), extension_id());
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params->menu_item_id.as_string)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    id.string_uid = *params->menu_item_id.as_string;
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (params->menu_item_id.as_integer)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    id.uid = *params->menu_item_id.as_integer;
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItem* item = manager->GetItemById(id);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure one extension can't remove another's menu items.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item || item->extension_id() != extension_id()) {
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_ = ErrorUtils::FormatErrorMessage(
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kCannotFindItemError, GetIDString(id));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!manager->RemoveContextMenuItem(id))
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manager->WriteToStorage(GetExtension());
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ContextMenusRemoveAllFunction::RunImpl() {
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MenuManager* manager = MenuManager::Get(GetProfile());
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manager->RemoveAllContextItems(GetExtension()->id());
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manager->WriteToStorage(GetExtension());
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
389