1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_context_menu_api.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_error_utils.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kCheckedKey[] = "checked";
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kContextsKey[] = "contexts";
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kDocumentUrlPatternsKey[] = "documentUrlPatterns";
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kGeneratedIdKey[] = "generatedId";
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kParentIdKey[] = "parentId";
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kTargetUrlPatternsKey[] = "targetUrlPatterns";
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kTitleKey[] = "title";
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kTypeKey[] = "type";
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kCannotFindItemError[] = "Cannot find menu item with id *";
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kCheckedError[] =
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "Only items with type \"radio\" or \"checkbox\" can be checked";
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kInvalidURLPatternError[] = "Invalid url pattern '*'";
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kInvalidValueError[] = "Invalid value for *";
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kInvalidTypeStringError[] = "Invalid type string '*'";
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kParentsMustBeNormalError[] =
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "Parent items must have type \"normal\"";
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kTitleNeededError[] =
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "All menu items except for separators must have a title";
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionContextMenuFunction::ParseContexts(
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DictionaryValue& properties,
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const char* key,
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionMenuItem::ContextList* result) {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* list = NULL;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.GetList(key, &list)) {
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem::ContextList tmp_result;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string value;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < list->GetSize(); i++) {
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!list->GetString(i, &value))
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (value == "all") {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::ALL);
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "page") {
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::PAGE);
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "selection") {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::SELECTION);
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "link") {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::LINK);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "editable") {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::EDITABLE);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "image") {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::IMAGE);
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "video") {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::VIDEO);
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (value == "audio") {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tmp_result.Add(ExtensionMenuItem::AUDIO);
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else if (value == "frame") {
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tmp_result.Add(ExtensionMenuItem::FRAME);
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidValueError, key);
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *result = tmp_result;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionContextMenuFunction::ParseType(
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DictionaryValue& properties,
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ExtensionMenuItem::Type& default_value,
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionMenuItem::Type* result) {
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(result);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.HasKey(kTypeKey)) {
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *result = default_value;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string type_string;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.GetString(kTypeKey, &type_string))
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type_string == "normal") {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *result = ExtensionMenuItem::NORMAL;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type_string == "checkbox") {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *result = ExtensionMenuItem::CHECKBOX;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type_string == "radio") {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *result = ExtensionMenuItem::RADIO;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type_string == "separator") {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *result = ExtensionMenuItem::SEPARATOR;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidTypeStringError,
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     type_string);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionContextMenuFunction::ParseChecked(
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionMenuItem::Type type,
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DictionaryValue& properties,
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool default_value,
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool* checked) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.HasKey(kCheckedKey)) {
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *checked = default_value;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.GetBoolean(kCheckedKey, checked))
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (checked && type != ExtensionMenuItem::CHECKBOX &&
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      type != ExtensionMenuItem::RADIO) {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = kCheckedError;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionContextMenuFunction::ParseURLPatterns(
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DictionaryValue& properties,
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const char* key,
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionExtent* result) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.HasKey(key))
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* list = NULL;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.GetList(key, &list))
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ListValue::iterator i = list->begin(); i != list->end(); ++i) {
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string tmp;
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!(*i)->GetAsString(&tmp))
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    URLPattern pattern(ExtensionMenuManager::kAllowedSchemes);
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // TODO(skerner):  Consider enabling strict pattern parsing
144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // if this extension's location indicates that it is under development.
145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (URLPattern::PARSE_SUCCESS != pattern.Parse(tmp,
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                                   URLPattern::PARSE_LENIENT)) {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       tmp);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->AddPattern(pattern);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionContextMenuFunction::SetURLPatterns(
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DictionaryValue& properties,
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionMenuItem* item) {
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Process the documentUrlPattern value.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionExtent document_url_patterns;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseURLPatterns(properties, kDocumentUrlPatternsKey,
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        &document_url_patterns))
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!document_url_patterns.is_empty()) {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    item->set_document_url_patterns(document_url_patterns);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Process the targetUrlPattern value.
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionExtent target_url_patterns;
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseURLPatterns(properties, kTargetUrlPatternsKey,
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        &target_url_patterns))
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!target_url_patterns.is_empty()) {
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    item->set_target_url_patterns(target_url_patterns);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionContextMenuFunction::GetParent(
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const DictionaryValue& properties,
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ExtensionMenuManager& manager,
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionMenuItem** result) {
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!properties.HasKey(kParentIdKey))
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (properties.HasKey(kParentIdKey) &&
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      !properties.GetInteger(kParentIdKey, &parent_id.uid))
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem* parent = manager.GetItemById(parent_id);
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parent) {
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    error_ = "Cannot find menu item with id " +
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        base::IntToString(parent_id.uid);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parent->type() != ExtensionMenuItem::NORMAL) {
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = kParentsMustBeNormalError;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *result = parent;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateContextMenuFunction::RunImpl() {
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* properties;
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &properties));
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(properties != NULL);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionMenuItem::Id id(profile(), extension_id(), 0);
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kGeneratedIdKey,
214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                                     &id.uid));
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string title;
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (properties->HasKey(kTitleKey) &&
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !properties->GetString(kTitleKey, &title))
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuManager* menu_manager =
22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      profile()->GetExtensionService()->menu_manager();
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem::ContextList contexts(ExtensionMenuItem::PAGE);
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseContexts(*properties, kContextsKey, &contexts))
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem::Type type;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseType(*properties, ExtensionMenuItem::NORMAL, &type))
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (title.empty() && type != ExtensionMenuItem::SEPARATOR) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = kTitleNeededError;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool checked;
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseChecked(type, *properties, false, &checked))
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<ExtensionMenuItem> item(
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new ExtensionMenuItem(id, title, checked, type, contexts));
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!SetURLPatterns(*properties, item.get()))
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = true;
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (properties->HasKey(kParentIdKey)) {
248513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kParentIdKey,
250513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                                       &parent_id.uid));
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionMenuItem* parent = menu_manager->GetItemById(parent_id);
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = ExtensionErrorUtils::FormatErrorMessage(
254513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          kCannotFindItemError, base::IntToString(parent_id.uid));
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parent->type() != ExtensionMenuItem::NORMAL) {
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = kParentsMustBeNormalError;
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    success = menu_manager->AddChildItem(parent_id, item.release());
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    success = menu_manager->AddContextItem(GetExtension(), item.release());
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!success)
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UpdateContextMenuFunction::RunImpl() {
273513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionMenuItem::Id item_id(profile(), extension_id(), 0);
274513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.uid));
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile()->GetExtensionService();
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuManager* manager = service->menu_manager();
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem* item = manager->GetItemById(item_id);
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!item || item->extension_id() != extension_id()) {
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
281513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        kCannotFindItemError, base::IntToString(item_id.uid));
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue *properties = NULL;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &properties));
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(properties != NULL);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuManager* menu_manager =
29021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      profile()->GetExtensionService()->menu_manager();
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Type.
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem::Type type;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseType(*properties, item->type(), &type))
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type != item->type())
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    item->set_type(type);
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Title.
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (properties->HasKey(kTitleKey)) {
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string title;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(properties->GetString(kTitleKey, &title));
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (title.empty() && type != ExtensionMenuItem::SEPARATOR) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = kTitleNeededError;
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    item->set_title(title);
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Checked state.
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool checked;
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseChecked(item->type(), *properties, item->checked(), &checked))
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (checked != item->checked()) {
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!item->SetChecked(checked))
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Contexts.
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem::ContextList contexts(item->contexts());
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ParseContexts(*properties, kContextsKey, &contexts))
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (contexts != item->contexts())
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    item->set_contexts(contexts);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Parent id.
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem* parent = NULL;
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetParent(*properties, *menu_manager, &parent))
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parent && !menu_manager->ChangeParent(item->id(), &parent->id()))
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!SetURLPatterns(*properties, item))
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RemoveContextMenuFunction::RunImpl() {
340513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ExtensionMenuItem::Id id(profile(), extension_id(), 0);
341513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.uid));
34221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile()->GetExtensionService();
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuManager* manager = service->menu_manager();
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuItem* item = manager->GetItemById(id);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ensure one extension can't remove another's menu items.
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!item || item->extension_id() != extension_id()) {
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
349513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        kCannotFindItemError, base::IntToString(id.uid));
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return manager->RemoveContextMenuItem(id);
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RemoveAllContextMenusFunction::RunImpl() {
35721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile()->GetExtensionService();
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionMenuManager* manager = service->menu_manager();
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  manager->RemoveAllContextItems(extension_id());
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
362