OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_file_browser_private_api.h" | 5 #include "chrome/browser/extensions/extension_file_browser_private_api.h" |
6 | 6 |
7 #include "base/base64.h" | |
8 #include "base/command_line.h" | |
7 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
8 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/singleton.h" | |
12 #include "base/stringprintf.h" | |
13 #include "base/string_util.h" | |
9 #include "base/task.h" | 14 #include "base/task.h" |
10 #include "base/values.h" | 15 #include "base/values.h" |
11 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/extensions/extension_event_router.h" | |
18 #include "chrome/browser/extensions/extension_function_dispatcher.h" | |
19 #include "chrome/browser/extensions/extension_service.h" | |
20 #include "chrome/browser/ui/webui/extension_icon_source.h" | |
21 #include "chrome/common/chrome_switches.h" | |
12 #include "chrome/common/extensions/extension.h" | 22 #include "chrome/common/extensions/extension.h" |
23 #include "chrome/common/extensions/file_browser_action.h" | |
13 #include "content/browser/browser_thread.h" | 24 #include "content/browser/browser_thread.h" |
25 #include "content/browser/child_process_security_policy.h" | |
26 #include "content/browser/renderer_host/render_process_host.h" | |
27 #include "content/browser/renderer_host/render_view_host.h" | |
14 #include "content/browser/tab_contents/tab_contents.h" | 28 #include "content/browser/tab_contents/tab_contents.h" |
15 #include "grit/generated_resources.h" | 29 #include "grit/generated_resources.h" |
16 #include "webkit/fileapi/file_system_context.h" | 30 #include "webkit/fileapi/file_system_context.h" |
31 #include "webkit/fileapi/file_system_mount_point_provider.h" | |
17 #include "webkit/fileapi/file_system_operation.h" | 32 #include "webkit/fileapi/file_system_operation.h" |
18 #include "webkit/fileapi/file_system_path_manager.h" | 33 #include "webkit/fileapi/file_system_path_manager.h" |
19 #include "webkit/fileapi/file_system_types.h" | 34 #include "webkit/fileapi/file_system_types.h" |
35 #include "webkit/fileapi/file_system_util.h" | |
20 #include "ui/base/l10n/l10n_util.h" | 36 #include "ui/base/l10n/l10n_util.h" |
21 | 37 |
38 // Error messages. | |
39 const char kFileError[] = "File error %d"; | |
40 const char kInvalidFileUrl[] = "Invalid file URL"; | |
41 | |
42 const int kReadOnlyFilePermissions = base::PLATFORM_FILE_OPEN | | |
43 base::PLATFORM_FILE_READ | | |
44 base::PLATFORM_FILE_EXCLUSIVE_READ | | |
45 base::PLATFORM_FILE_ASYNC; | |
46 | |
47 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN | | |
48 base::PLATFORM_FILE_CREATE | | |
49 base::PLATFORM_FILE_OPEN_ALWAYS | | |
50 base::PLATFORM_FILE_CREATE_ALWAYS | | |
51 base::PLATFORM_FILE_READ | | |
52 base::PLATFORM_FILE_WRITE | | |
53 base::PLATFORM_FILE_EXCLUSIVE_READ | | |
54 base::PLATFORM_FILE_EXCLUSIVE_WRITE | | |
55 base::PLATFORM_FILE_ASYNC | | |
56 base::PLATFORM_FILE_TRUNCATE | | |
57 base::PLATFORM_FILE_WRITE_ATTRIBUTES; | |
58 | |
59 typedef std::vector< | |
60 std::pair<std::string, const FileBrowserAction* > > | |
Aaron Boodman
2011/04/12 22:47:21
Consider defining a struct. It is a bit more reada
| |
61 NamedActionList; | |
62 | |
63 typedef std::vector<const FileBrowserAction*> ActionList; | |
64 | |
65 bool GetFileBrowserActions(Profile* profile, | |
66 const GURL& selected_file_url, | |
67 ActionList* results) { | |
68 ExtensionService* service = profile->GetExtensionService(); | |
69 if (!service) | |
70 return false; // In unit-tests, we may not have an ExtensionService. | |
71 | |
72 for (ExtensionList::const_iterator iter = service->extensions()->begin(); | |
73 iter != service->extensions()->end(); | |
74 ++iter) { | |
75 const Extension* extension = iter->get(); | |
76 if (!extension->file_browser_actions()) | |
77 continue; | |
78 | |
79 for (Extension::FileBrowserActionList::const_iterator action_iter = | |
80 extension->file_browser_actions()->begin(); | |
81 action_iter != extension->file_browser_actions()->end(); | |
82 ++action_iter) { | |
83 const FileBrowserAction* action = action_iter->get(); | |
84 if (!action->MatchesURL(selected_file_url)) | |
85 continue; | |
86 | |
87 results->push_back(action_iter->get()); | |
88 } | |
89 } | |
90 return true; | |
91 } | |
92 | |
93 // Given the list of selected files, returns array of context menu tasks | |
94 // that are shared | |
95 bool FindCommonTasks(Profile* profile, | |
96 ListValue* files_list, | |
97 NamedActionList* named_action_list) { | |
98 named_action_list->clear(); | |
99 ActionList common_tasks; | |
100 for (size_t i = 0; i < files_list->GetSize(); ++i) { | |
101 std::string file_url; | |
102 if (!files_list->GetString(i, &file_url)) | |
103 return false; | |
104 | |
105 ActionList file_actions; | |
106 if (!GetFileBrowserActions(profile, GURL(file_url), &file_actions)) | |
107 return false; | |
108 // If there is nothing to do for one file, the intersection of tasks for all | |
109 // files will be empty at the end. | |
110 if (!file_actions.size()) { | |
111 common_tasks.clear(); | |
112 return true; | |
113 } | |
114 // For the very first file, just copy elements. | |
115 if (i == 0) { | |
116 common_tasks.insert(common_tasks.begin(), | |
117 file_actions.begin(), | |
Aaron Boodman
2011/04/12 22:47:21
indent--
zel
2011/04/13 17:49:55
Done.
| |
118 file_actions.end()); | |
119 std::sort(common_tasks.begin(), common_tasks.end()); | |
120 } else if (common_tasks.size()) { | |
121 // For all additional files, find intersection between the accumulated | |
122 // and file specific set. | |
123 std::sort(file_actions.begin(), file_actions.end()); | |
124 ActionList intersection(common_tasks.size()); | |
125 ActionList::iterator intersection_end = | |
126 std::set_intersection(common_tasks.begin(), | |
127 common_tasks.end(), | |
128 file_actions.begin(), | |
129 file_actions.end(), | |
130 intersection.begin()); | |
131 common_tasks.clear(); | |
132 common_tasks.insert(common_tasks.begin(), | |
133 intersection.begin(), | |
Aaron Boodman
2011/04/12 22:47:21
indent--
zel
2011/04/13 17:49:55
Done.
| |
134 intersection_end); | |
135 std::sort(common_tasks.begin(), common_tasks.end()); | |
136 } | |
137 } | |
138 | |
139 // At the end, sort the results by task title. | |
140 // TODO(zelidrag): Wire this with ICU to make this sort I18N happy. | |
141 for (ActionList::const_iterator iter = | |
142 common_tasks.begin(); | |
Aaron Boodman
2011/04/12 22:47:21
Move this line onto previous?
zel
2011/04/13 17:49:55
Done.
| |
143 iter != common_tasks.end(); ++iter) { | |
144 named_action_list->push_back( | |
145 std::pair<std::string, const FileBrowserAction* >( | |
146 (*iter)->default_title(), *iter)); | |
147 } | |
148 std::sort(named_action_list->begin(), named_action_list->end()); | |
Aaron Boodman
2011/04/12 22:47:21
Is the only reason for named_action_list so that y
zel
2011/04/13 17:49:55
I know, that is what I was planning to do with my
| |
149 return true; | |
150 } | |
151 | |
152 // Breaks down task_id that is used between getFileTasks() and executeTask() on | |
153 // its building blocks. task_id field the following structure: | |
154 // <task-type>:<extension-id>/<task-action-id> | |
155 // Currently, the only supported task-type is of 'context'. | |
156 bool CrackTaskIdentifier(const std::string& task_id, | |
157 std::string* target_extension_id, | |
158 std::string* action_id) { | |
159 std::vector<std::string> result; | |
160 int count = Tokenize(task_id, std::string("|"), &result); | |
161 if (count != 2) | |
162 return false; | |
163 *target_extension_id = result[0]; | |
164 *action_id = result[1]; | |
165 return true; | |
166 } | |
167 | |
168 std::string MakeTaskID(const char* extension_id, | |
169 const char* action_id) { | |
170 return base::StringPrintf("%s|%s", extension_id, action_id); | |
171 } | |
22 | 172 |
23 class LocalFileSystemCallbackDispatcher | 173 class LocalFileSystemCallbackDispatcher |
24 : public fileapi::FileSystemCallbackDispatcher { | 174 : public fileapi::FileSystemCallbackDispatcher { |
25 public: | 175 public: |
26 explicit LocalFileSystemCallbackDispatcher( | 176 explicit LocalFileSystemCallbackDispatcher( |
27 RequestLocalFileSystemFunction* function) : function_(function) { | 177 RequestLocalFileSystemFunctionBase* function, |
178 Profile* profile, | |
179 int child_id, | |
180 const GURL& source_url, | |
181 const GURL& file_url) | |
182 : function_(function), | |
183 profile_(profile), | |
184 child_id_(child_id), | |
185 source_url_(source_url), | |
186 file_url_(file_url) { | |
28 DCHECK(function_); | 187 DCHECK(function_); |
29 } | 188 } |
189 | |
30 // fileapi::FileSystemCallbackDispatcher overrides. | 190 // fileapi::FileSystemCallbackDispatcher overrides. |
31 virtual void DidSucceed() OVERRIDE { | 191 virtual void DidSucceed() OVERRIDE { |
32 NOTREACHED(); | 192 NOTREACHED(); |
33 } | 193 } |
194 | |
34 virtual void DidReadMetadata(const base::PlatformFileInfo& info, | 195 virtual void DidReadMetadata(const base::PlatformFileInfo& info, |
35 const FilePath& unused) OVERRIDE { | 196 const FilePath& unused) OVERRIDE { |
36 NOTREACHED(); | 197 NOTREACHED(); |
37 } | 198 } |
199 | |
38 virtual void DidReadDirectory( | 200 virtual void DidReadDirectory( |
39 const std::vector<base::FileUtilProxy::Entry>& entries, | 201 const std::vector<base::FileUtilProxy::Entry>& entries, |
40 bool has_more) OVERRIDE { | 202 bool has_more) OVERRIDE { |
41 NOTREACHED(); | 203 NOTREACHED(); |
42 } | 204 } |
205 | |
43 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE { | 206 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE { |
44 NOTREACHED(); | 207 NOTREACHED(); |
45 } | 208 } |
209 | |
46 virtual void DidOpenFileSystem(const std::string& name, | 210 virtual void DidOpenFileSystem(const std::string& name, |
47 const FilePath& path) OVERRIDE { | 211 const FilePath& root_path) OVERRIDE { |
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
213 // Set up file permission access. | |
214 if (!file_url_.is_empty()) { | |
215 if (!SetupFileAccessPermissions()) { | |
216 DidFail(base::PLATFORM_FILE_ERROR_SECURITY); | |
217 return; | |
218 } | |
219 } else if (!SetupFileSystemAccessPermissions()) { | |
220 DidFail(base::PLATFORM_FILE_ERROR_SECURITY); | |
221 return; | |
222 } | |
223 | |
48 BrowserThread::PostTask( | 224 BrowserThread::PostTask( |
49 BrowserThread::UI, FROM_HERE, | 225 BrowserThread::UI, FROM_HERE, |
50 NewRunnableMethod(function_, | 226 NewRunnableMethod(function_, |
51 &RequestLocalFileSystemFunction::RespondSuccessOnUIThread, | 227 &RequestLocalFileSystemFunctionBase::RespondSuccessOnUIThread, |
52 name, | 228 name, |
53 path)); | 229 root_path, |
54 } | 230 file_url_)); |
231 } | |
232 | |
55 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE { | 233 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE { |
56 BrowserThread::PostTask( | 234 BrowserThread::PostTask( |
57 BrowserThread::UI, FROM_HERE, | 235 BrowserThread::UI, FROM_HERE, |
58 NewRunnableMethod(function_, | 236 NewRunnableMethod(function_, |
59 &RequestLocalFileSystemFunction::RespondFailedOnUIThread, | 237 &RequestLocalFileSystemFunctionBase::RespondFailedOnUIThread, |
60 error_code)); | 238 error_code)); |
61 } | 239 } |
240 | |
62 private: | 241 private: |
63 RequestLocalFileSystemFunction* function_; | 242 |
243 const Extension* GetExtension() { | |
Aaron Boodman
2011/04/12 22:47:21
You can also just pass Extension* into LocalFileSy
zel
2011/04/13 17:49:55
Done.
| |
244 std::string extension_id = source_url_.GetOrigin().host(); | |
245 ExtensionService* service = profile_->GetExtensionService(); | |
246 if (!service) | |
247 return NULL; | |
248 return service->GetExtensionById(extension_id, | |
249 false); // include_disabled | |
250 } | |
251 | |
252 // Checks legitimacy of file url and grants RO access permissions for that | |
253 // file to the target renderer process. | |
254 bool SetupFileAccessPermissions() { | |
255 | |
Aaron Boodman
2011/04/12 22:47:21
Unnecessary whitespace.
zel
2011/04/13 17:49:55
this method is no more
| |
256 const Extension* extension = GetExtension(); | |
257 if (!extension) | |
258 return false; | |
259 | |
260 GURL file_origin_url; | |
261 FilePath virtual_path; | |
262 fileapi::FileSystemType type; | |
263 fileapi::FileSystemPathManager* path_manager = | |
264 profile_->GetFileSystemContext()->path_manager(); | |
265 if (!path_manager->CrackFileSystemPath(FilePath(file_url_.spec()), | |
266 &file_origin_url, &type, | |
267 &virtual_path)) { | |
268 return false; | |
269 } | |
270 | |
271 if (type != fileapi::kFileSystemTypeLocal) | |
272 return false; | |
273 | |
274 // Make sure this url really being used by the right caller extension. | |
275 if (source_url_.GetOrigin() != file_origin_url) { | |
276 DidFail(base::PLATFORM_FILE_ERROR_SECURITY); | |
277 return false; | |
278 } | |
279 FilePath root_path = path_manager->GetFileSystemRootPathOnFileThread( | |
280 file_origin_url, | |
281 fileapi::kFileSystemTypeLocal, | |
282 virtual_path, | |
283 false); // create | |
284 FilePath finalFilePath = root_path.Append(virtual_path); | |
285 | |
286 // TODO(zelidrag): Add explicit R/W + R/O permissions for non-component | |
287 // extensions. | |
288 | |
289 // Grant R/O access permission to non-component extension and R/W to | |
290 // component extensions. | |
291 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile( | |
292 child_id_, finalFilePath, | |
293 extension->location() != Extension::COMPONENT ? | |
294 kReadOnlyFilePermissions : kReadWriteFilePermissions); | |
295 return true; | |
296 } | |
297 | |
298 // Grants file system access permissions to file browser component. | |
299 bool SetupFileSystemAccessPermissions() { | |
300 const Extension* extension = GetExtension(); | |
301 if (!extension) | |
302 return false; | |
303 | |
304 // Make sure that only component extension can access the entire | |
305 // local file system. | |
306 if (extension->location() != Extension::COMPONENT | |
307 #ifndef NDEBUG | |
308 && !CommandLine::ForCurrentProcess()->HasSwitch( | |
309 switches::kExposePrivateExtensionApi) | |
Aaron Boodman
2011/04/12 22:47:21
Same question with this as in other places.
zel
2011/04/13 17:49:55
same issue with compilation, will look at it later
| |
310 #endif | |
311 ) { | |
312 NOTREACHED() << "Private method access by non-component extension " | |
313 << extension->id(); | |
314 return false; | |
315 } | |
316 | |
317 fileapi::FileSystemPathManager* path_manager = | |
318 profile_->GetFileSystemContext()->path_manager(); | |
319 fileapi::FileSystemMountPointProvider* provider = | |
320 path_manager->local_provider(); | |
321 if (!provider) | |
322 return false; | |
323 | |
324 // Grant R/W file permissions to the renderer hosting component | |
325 // extension for all paths exposed by our local file system provider. | |
326 std::vector<FilePath> root_dirs = provider->GetRootDirectories(); | |
327 for (std::vector<FilePath>::iterator iter = root_dirs.begin(); | |
328 iter != root_dirs.end(); | |
329 ++iter) { | |
330 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile( | |
331 child_id_, *iter, kReadWriteFilePermissions); | |
332 } | |
333 return true; | |
334 } | |
335 | |
336 RequestLocalFileSystemFunctionBase* function_; | |
337 Profile* profile_; | |
338 // Renderer process id. | |
339 int child_id_; | |
340 // Extension source URL. | |
341 GURL source_url_; | |
342 GURL file_url_; | |
64 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher); | 343 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher); |
65 }; | 344 }; |
66 | 345 |
67 RequestLocalFileSystemFunction::RequestLocalFileSystemFunction() { | 346 void RequestLocalFileSystemFunctionBase::RequestOnFileThread( |
68 } | 347 const GURL& source_url, const GURL& file_url) { |
69 | |
70 RequestLocalFileSystemFunction::~RequestLocalFileSystemFunction() { | |
71 } | |
72 | |
73 bool RequestLocalFileSystemFunction::RunImpl() { | |
74 fileapi::FileSystemOperation* operation = | 348 fileapi::FileSystemOperation* operation = |
75 new fileapi::FileSystemOperation( | 349 new fileapi::FileSystemOperation( |
76 new LocalFileSystemCallbackDispatcher(this), | 350 new LocalFileSystemCallbackDispatcher( |
351 this, | |
352 profile(), | |
353 dispatcher()->render_view_host()->process()->id(), | |
354 source_url, | |
355 file_url), | |
77 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | 356 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), |
78 profile()->GetFileSystemContext(), | 357 profile()->GetFileSystemContext(), |
79 NULL); | 358 NULL); |
80 GURL origin_url = source_url().GetOrigin(); | 359 GURL origin_url = source_url.GetOrigin(); |
81 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal, | 360 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeLocal, |
82 false); // create | 361 false); // create |
362 } | |
363 | |
364 bool RequestLocalFileSystemFunctionBase::RunImpl() { | |
365 std::string file_url; | |
366 if (args_->GetSize()) | |
367 args_->GetString(0, &file_url); | |
368 BrowserThread::PostTask( | |
369 BrowserThread::FILE, FROM_HERE, | |
370 NewRunnableMethod(this, | |
371 &RequestLocalFileSystemFunctionBase::RequestOnFileThread, | |
372 source_url_, | |
373 GURL(file_url))); | |
83 // Will finish asynchronously. | 374 // Will finish asynchronously. |
84 return true; | 375 return true; |
85 } | 376 } |
86 | 377 |
87 void RequestLocalFileSystemFunction::RespondSuccessOnUIThread( | 378 void RequestLocalFileSystemFunctionBase::RespondSuccessOnUIThread( |
88 const std::string& name, const FilePath& path) { | 379 const std::string& name, const FilePath& root_path, |
380 const GURL& file_url) { | |
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
90 result_.reset(new DictionaryValue()); | 382 result_.reset(new DictionaryValue()); |
91 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); | 383 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); |
92 dict->SetString("name", name); | 384 dict->SetString("name", name); |
93 dict->SetString("path", path.value()); | 385 dict->SetString("path", root_path.value()); |
94 dict->SetInteger("error", base::PLATFORM_FILE_OK); | 386 dict->SetInteger("error", base::PLATFORM_FILE_OK); |
387 if (!file_url.is_empty() && file_url.is_valid()) | |
388 dict->SetString("fileUrl", file_url.spec()); | |
95 SendResponse(true); | 389 SendResponse(true); |
96 } | 390 } |
97 | 391 |
98 void RequestLocalFileSystemFunction::RespondFailedOnUIThread( | 392 void RequestLocalFileSystemFunctionBase::RespondFailedOnUIThread( |
99 base::PlatformFileError error_code) { | 393 base::PlatformFileError error_code) { |
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
101 result_.reset(new DictionaryValue()); | 395 error_ = base::StringPrintf(kFileError, static_cast<int>(error_code)); |
102 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get()); | 396 SendResponse(false); |
103 dict->SetInteger("error", static_cast<int>(error_code)); | 397 } |
398 | |
399 bool GetFileTasksFileBrowserFunction::RunImpl() { | |
400 ListValue* files_list = NULL; | |
401 if (!args_->GetList(0, &files_list)) | |
402 return false; | |
403 | |
404 result_.reset(new ListValue()); | |
405 ListValue* result_list = reinterpret_cast<ListValue*>(result_.get()); | |
Aaron Boodman
2011/04/12 22:47:21
You can avoid the cast with:
ListValue* result_li
zel
2011/04/13 17:49:55
Done.
| |
406 | |
407 NamedActionList common_tasks; | |
408 if (!FindCommonTasks(profile_, files_list, &common_tasks)) | |
409 return false; | |
410 | |
411 ExtensionService* service = profile_->GetExtensionService(); | |
412 for (NamedActionList::iterator iter = common_tasks.begin(); | |
413 iter != common_tasks.end(); | |
414 ++iter) { | |
415 const std::string extension_id = iter->second->extension_id(); | |
416 const Extension* extension = service->GetExtensionById(extension_id, false); | |
417 if (!extension) { | |
Aaron Boodman
2011/04/12 22:47:21
This should probably be a CHECK. Is there any legi
zel
2011/04/13 17:49:55
Done.
| |
418 LOG(WARNING) << "Disabled extension!?" << extension_id; | |
419 continue; | |
420 } | |
421 DictionaryValue* task = new DictionaryValue(); | |
422 task->SetString("taskId", MakeTaskID(extension_id.data(), | |
423 iter->second->id().data())); | |
424 task->SetString("title", iter->second->default_title()); | |
425 // TODO(zelidrag): Figure out how to expose icon URL that task defined in | |
426 // manifest instead of the default extension icon. | |
427 GURL icon = | |
428 ExtensionIconSource::GetIconURL(extension, | |
429 Extension::EXTENSION_ICON_SMALLISH, | |
430 ExtensionIconSet::MATCH_BIGGER, | |
431 false); // grayscale | |
432 task->SetString("iconUrl", icon.spec()); | |
433 result_list->Append(task); | |
434 } | |
435 | |
436 // TODO(zelidrag, serya): Add intent content tasks to result_list once we | |
437 // implement that API. | |
104 SendResponse(true); | 438 SendResponse(true); |
439 return true; | |
440 } | |
441 | |
442 bool ExecuteTasksFileBrowserFunction::RunImpl() { | |
443 // First param is task id that was to the extension with getFileTasks call. | |
444 std::string task_id; | |
445 if (!args_->GetString(0, &task_id) || !task_id.size()) | |
446 return false; | |
447 | |
448 // The second param is the list of files that need to be executed with this | |
449 // task. | |
450 ListValue* files_list = NULL; | |
451 if (!args_->GetList(1, &files_list)) | |
452 return false; | |
453 | |
454 if (!files_list->GetSize()) | |
455 return true; | |
456 | |
457 std::string target_extension_id; | |
458 std::string action_id; | |
459 if (!CrackTaskIdentifier(task_id, &target_extension_id, | |
460 &action_id)) { | |
461 return false; | |
462 } | |
463 | |
464 ExecuteContextMenuTasks(target_extension_id, action_id, files_list); | |
465 SendResponse(true); | |
466 return true; | |
467 } | |
468 | |
469 bool ExecuteTasksFileBrowserFunction::GrantLocalFileSystemAccess( | |
470 const GURL& origin_file_url, | |
471 const std::string& extension_id, | |
472 GURL* target_file_url) { | |
473 GURL file_origin_url; | |
474 FilePath virtual_path; | |
475 fileapi::FileSystemType type; | |
476 // Breakdown file URL. | |
477 fileapi::FileSystemPathManager* path_manager = | |
478 profile_->GetFileSystemContext()->path_manager(); | |
479 if (!path_manager->CrackFileSystemPath(FilePath(origin_file_url.spec()), | |
480 &file_origin_url, &type, | |
481 &virtual_path)) { | |
482 return false; | |
483 } | |
484 | |
485 if (type != fileapi::kFileSystemTypeLocal) | |
486 return false; | |
487 | |
488 // Grant access to this particular file to target extension. | |
489 GURL target_origin_url(Extension::GetBaseURLFromExtensionId(extension_id)); | |
490 fileapi::FileSystemMountPointProvider* provider = | |
491 path_manager->local_provider(); | |
492 if (!provider) | |
493 return false; | |
494 provider->GrantAccess(target_origin_url, virtual_path); | |
495 GURL base_url = fileapi::GetFileSystemRootURI(target_origin_url, | |
496 fileapi::kFileSystemTypeLocal); | |
497 *target_file_url = GURL(base_url.spec() + virtual_path.value()); | |
498 return true; | |
499 } | |
500 | |
501 bool ExecuteTasksFileBrowserFunction::ExecuteContextMenuTasks( | |
502 const std::string& handler_extension_id, const std::string& action_id, | |
503 ListValue* files_list) { | |
504 ExtensionService* service = profile_->GetExtensionService(); | |
505 if (!service) | |
506 return NULL; | |
507 | |
508 const Extension* extension = service->GetExtensionById(handler_extension_id, | |
509 false); | |
Aaron Boodman
2011/04/12 22:47:21
ExtensionFunction has a GetExtension() method.
zel
2011/04/13 17:49:55
yes, but that one gives me extension that is execu
| |
510 if (!extension) | |
511 return NULL; | |
512 | |
513 ExtensionEventRouter* event_router = profile_->GetExtensionEventRouter(); | |
514 if (!event_router) | |
515 return false; | |
516 | |
517 scoped_ptr<ListValue> event_args(new ListValue()); | |
518 ListValue* files_urls = new ListValue(); | |
519 event_args->Append(Value::CreateStringValue(action_id)); | |
520 event_args->Append(files_urls); | |
521 for (size_t i = 0; i < files_list->GetSize(); i++) { | |
522 std::string origin_file_url; | |
523 if (!files_list->GetString(i, &origin_file_url)) { | |
524 error_ = kInvalidFileUrl; | |
525 SendResponse(false); | |
526 return false; | |
527 } | |
528 GURL handler_file_url; | |
529 if (!GrantLocalFileSystemAccess(GURL(origin_file_url), | |
530 handler_extension_id, | |
531 &handler_file_url)) { | |
532 error_ = kInvalidFileUrl; | |
533 SendResponse(false); | |
534 return false; | |
535 } | |
536 files_urls->Append(Value::CreateStringValue(handler_file_url.spec())); | |
537 } | |
538 std::string json_args; | |
539 base::JSONWriter::Write(event_args.get(), false, &json_args); | |
540 std::string event_name = "contextMenus"; | |
541 event_router->DispatchEventToExtension( | |
542 handler_extension_id, std::string("fileSystem.onExecuteAction"), | |
543 json_args, profile_, | |
544 GURL()); | |
545 | |
546 result_.reset(new FundamentalValue(true)); | |
547 SendResponse(true); | |
548 return true; | |
105 } | 549 } |
106 | 550 |
107 FileDialogFunction::FileDialogFunction() { | 551 FileDialogFunction::FileDialogFunction() { |
108 } | 552 } |
109 | 553 |
110 FileDialogFunction::~FileDialogFunction() { | 554 FileDialogFunction::~FileDialogFunction() { |
111 } | 555 } |
112 | 556 |
113 // static | 557 // static |
114 FileDialogFunction::ListenerMap FileDialogFunction::listener_map_; | 558 FileDialogFunction::ListenerMap FileDialogFunction::listener_map_; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
289 SET_STRING(IDS_FILE_BROWSER, COMPUTING_SELECTION); | 733 SET_STRING(IDS_FILE_BROWSER, COMPUTING_SELECTION); |
290 SET_STRING(IDS_FILE_BROWSER, NOTHING_SELECTED); | 734 SET_STRING(IDS_FILE_BROWSER, NOTHING_SELECTED); |
291 SET_STRING(IDS_FILE_BROWSER, ONE_FILE_SELECTED); | 735 SET_STRING(IDS_FILE_BROWSER, ONE_FILE_SELECTED); |
292 SET_STRING(IDS_FILE_BROWSER, MANY_FILES_SELECTED); | 736 SET_STRING(IDS_FILE_BROWSER, MANY_FILES_SELECTED); |
293 | 737 |
294 #undef SET_STRING | 738 #undef SET_STRING |
295 | 739 |
296 SendResponse(true); | 740 SendResponse(true); |
297 return true; | 741 return true; |
298 } | 742 } |
743 | |
Aaron Boodman
2011/04/12 22:47:21
Unnecessary newline?
zel
2011/04/13 17:49:55
Done.
| |
OLD | NEW |