1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_drive.h" 6 7 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/chromeos/drive/drive_integration_service.h" 9 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" 10 #include "chrome/browser/chromeos/file_manager/file_tasks.h" 11 #include "chrome/browser/chromeos/file_manager/fileapi_util.h" 12 #include "chrome/browser/chromeos/file_manager/url_util.h" 13 #include "chrome/browser/chromeos/fileapi/file_system_backend.h" 14 #include "chrome/browser/chromeos/login/users/user_manager.h" 15 #include "chrome/browser/drive/drive_app_registry.h" 16 #include "chrome/browser/drive/event_logger.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile_manager.h" 19 #include "chrome/common/extensions/api/file_browser_private.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "webkit/common/fileapi/file_system_info.h" 22 #include "webkit/common/fileapi/file_system_util.h" 23 24 using content::BrowserThread; 25 26 using file_manager::util::EntryDefinition; 27 using file_manager::util::EntryDefinitionCallback; 28 using file_manager::util::EntryDefinitionList; 29 using file_manager::util::EntryDefinitionListCallback; 30 using file_manager::util::FileDefinition; 31 using file_manager::util::FileDefinitionList; 32 using extensions::api::file_browser_private::DriveEntryProperties; 33 34 namespace extensions { 35 namespace { 36 37 // List of connection types of drive. 38 // Keep this in sync with the DriveConnectionType in common/js/util.js. 39 const char kDriveConnectionTypeOffline[] = "offline"; 40 const char kDriveConnectionTypeMetered[] = "metered"; 41 const char kDriveConnectionTypeOnline[] = "online"; 42 43 // List of reasons of kDriveConnectionType*. 44 // Keep this in sync with the DriveConnectionReason in common/js/util.js. 45 const char kDriveConnectionReasonNotReady[] = "not_ready"; 46 const char kDriveConnectionReasonNoNetwork[] = "no_network"; 47 const char kDriveConnectionReasonNoService[] = "no_service"; 48 49 // Copies properties from |entry_proto| to |properties|. |shared_with_me| is 50 // given from the running profile. 51 void FillDriveEntryPropertiesValue(const drive::ResourceEntry& entry_proto, 52 bool shared_with_me, 53 DriveEntryProperties* properties) { 54 properties->shared_with_me.reset(new bool(shared_with_me)); 55 properties->shared.reset(new bool(entry_proto.shared())); 56 57 const drive::PlatformFileInfoProto& file_info = entry_proto.file_info(); 58 properties->file_size.reset(new double(file_info.size())); 59 properties->last_modified_time.reset(new double( 60 base::Time::FromInternalValue(file_info.last_modified()).ToJsTime())); 61 62 if (!entry_proto.has_file_specific_info()) 63 return; 64 65 const drive::FileSpecificInfo& file_specific_info = 66 entry_proto.file_specific_info(); 67 68 if (!entry_proto.resource_id().empty()) { 69 properties->thumbnail_url.reset( 70 new std::string("https://www.googledrive.com/thumb/" + 71 entry_proto.resource_id() + "?width=500&height=500")); 72 } 73 if (file_specific_info.has_image_width()) { 74 properties->image_width.reset( 75 new int(file_specific_info.image_width())); 76 } 77 if (file_specific_info.has_image_height()) { 78 properties->image_height.reset( 79 new int(file_specific_info.image_height())); 80 } 81 if (file_specific_info.has_image_rotation()) { 82 properties->image_rotation.reset( 83 new int(file_specific_info.image_rotation())); 84 } 85 properties->is_hosted.reset( 86 new bool(file_specific_info.is_hosted_document())); 87 properties->content_mime_type.reset( 88 new std::string(file_specific_info.content_mime_type())); 89 90 properties->is_pinned.reset( 91 new bool(file_specific_info.cache_state().is_pinned())); 92 properties->is_present.reset( 93 new bool(file_specific_info.cache_state().is_present())); 94 } 95 96 // Creates entry definition list for (metadata) search result info list. 97 template <class T> 98 void ConvertSearchResultInfoListToEntryDefinitionList( 99 Profile* profile, 100 const std::string& extension_id, 101 const std::vector<T>& search_result_info_list, 102 const EntryDefinitionListCallback& callback) { 103 FileDefinitionList file_definition_list; 104 105 for (size_t i = 0; i < search_result_info_list.size(); ++i) { 106 FileDefinition file_definition; 107 file_definition.virtual_path = 108 file_manager::util::ConvertDrivePathToRelativeFileSystemPath( 109 profile, extension_id, search_result_info_list.at(i).path); 110 file_definition.is_directory = search_result_info_list.at(i).is_directory; 111 file_definition_list.push_back(file_definition); 112 } 113 114 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( 115 profile, 116 extension_id, 117 file_definition_list, // Safe, since copied internally. 118 callback); 119 } 120 121 class SingleDriveEntryPropertiesGetter { 122 public: 123 typedef base::Callback<void(drive::FileError error)> ResultCallback; 124 125 // Creates an instance and starts the process. 126 static void Start(const base::FilePath local_path, 127 linked_ptr<DriveEntryProperties> properties, 128 Profile* const profile, 129 const ResultCallback& callback) { 130 131 SingleDriveEntryPropertiesGetter* instance = 132 new SingleDriveEntryPropertiesGetter( 133 local_path, properties, profile, callback); 134 instance->StartProcess(); 135 136 // The instance will be destroyed by itself. 137 } 138 139 virtual ~SingleDriveEntryPropertiesGetter() {} 140 141 private: 142 // Given parameters. 143 const ResultCallback callback_; 144 const base::FilePath local_path_; 145 const linked_ptr<DriveEntryProperties> properties_; 146 Profile* const running_profile_; 147 148 // Values used in the process. 149 Profile* file_owner_profile_; 150 base::FilePath file_path_; 151 scoped_ptr<drive::ResourceEntry> owner_resource_entry_; 152 153 base::WeakPtrFactory<SingleDriveEntryPropertiesGetter> weak_ptr_factory_; 154 155 SingleDriveEntryPropertiesGetter(const base::FilePath local_path, 156 linked_ptr<DriveEntryProperties> properties, 157 Profile* const profile, 158 const ResultCallback& callback) 159 : callback_(callback), 160 local_path_(local_path), 161 properties_(properties), 162 running_profile_(profile), 163 file_owner_profile_(NULL), 164 weak_ptr_factory_(this) { 165 DCHECK(!callback_.is_null()); 166 DCHECK(profile); 167 } 168 169 base::WeakPtr<SingleDriveEntryPropertiesGetter> GetWeakPtr() { 170 return weak_ptr_factory_.GetWeakPtr(); 171 } 172 173 void StartProcess() { 174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 175 176 file_path_ = drive::util::ExtractDrivePath(local_path_); 177 file_owner_profile_ = drive::util::ExtractProfileFromPath(local_path_); 178 179 if (!file_owner_profile_ || 180 !g_browser_process->profile_manager()->IsValidProfile( 181 file_owner_profile_)) { 182 CompleteGetFileProperties(drive::FILE_ERROR_FAILED); 183 return; 184 } 185 186 // Start getting the file info. 187 drive::FileSystemInterface* const file_system = 188 drive::util::GetFileSystemByProfile(file_owner_profile_); 189 if (!file_system) { 190 // |file_system| is NULL if Drive is disabled or not mounted. 191 CompleteGetFileProperties(drive::FILE_ERROR_FAILED); 192 return; 193 } 194 195 file_system->GetResourceEntry( 196 file_path_, 197 base::Bind(&SingleDriveEntryPropertiesGetter::OnGetFileInfo, 198 GetWeakPtr())); 199 } 200 201 void OnGetFileInfo(drive::FileError error, 202 scoped_ptr<drive::ResourceEntry> entry) { 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 204 205 if (error != drive::FILE_ERROR_OK) { 206 CompleteGetFileProperties(error); 207 return; 208 } 209 210 DCHECK(entry); 211 owner_resource_entry_.swap(entry); 212 213 if (running_profile_->IsSameProfile(file_owner_profile_)) { 214 StartParseFileInfo(owner_resource_entry_->shared_with_me()); 215 return; 216 } 217 218 // If the running profile does not own the file, obtain the shared_with_me 219 // flag from the running profile's value. 220 drive::FileSystemInterface* const file_system = 221 drive::util::GetFileSystemByProfile(running_profile_); 222 if (!file_system) { 223 CompleteGetFileProperties(drive::FILE_ERROR_FAILED); 224 return; 225 } 226 file_system->GetPathFromResourceId( 227 owner_resource_entry_->resource_id(), 228 base::Bind(&SingleDriveEntryPropertiesGetter::OnGetRunningPath, 229 GetWeakPtr())); 230 } 231 232 void OnGetRunningPath(drive::FileError error, 233 const base::FilePath& file_path) { 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 235 236 if (error != drive::FILE_ERROR_OK) { 237 // The running profile does not know the file. 238 StartParseFileInfo(false); 239 return; 240 } 241 242 drive::FileSystemInterface* const file_system = 243 drive::util::GetFileSystemByProfile(running_profile_); 244 if (!file_system) { 245 // The drive is disable for the running profile. 246 StartParseFileInfo(false); 247 return; 248 } 249 250 file_system->GetResourceEntry( 251 file_path, 252 base::Bind(&SingleDriveEntryPropertiesGetter::OnGetShareInfo, 253 GetWeakPtr())); 254 } 255 256 void OnGetShareInfo(drive::FileError error, 257 scoped_ptr<drive::ResourceEntry> entry) { 258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 259 260 if (error != drive::FILE_ERROR_OK) { 261 CompleteGetFileProperties(error); 262 return; 263 } 264 265 DCHECK(entry); 266 StartParseFileInfo(entry->shared_with_me()); 267 } 268 269 void StartParseFileInfo(bool shared_with_me) { 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 271 272 FillDriveEntryPropertiesValue( 273 *owner_resource_entry_, shared_with_me, properties_.get()); 274 275 drive::FileSystemInterface* const file_system = 276 drive::util::GetFileSystemByProfile(file_owner_profile_); 277 drive::DriveAppRegistry* const app_registry = 278 drive::util::GetDriveAppRegistryByProfile(file_owner_profile_); 279 if (!file_system || !app_registry) { 280 // |file_system| or |app_registry| is NULL if Drive is disabled. 281 CompleteGetFileProperties(drive::FILE_ERROR_FAILED); 282 return; 283 } 284 285 // The properties meaningful for directories are already filled in 286 // FillDriveEntryPropertiesValue(). 287 if (!owner_resource_entry_->has_file_specific_info()) { 288 CompleteGetFileProperties(drive::FILE_ERROR_OK); 289 return; 290 } 291 292 const drive::FileSpecificInfo& file_specific_info = 293 owner_resource_entry_->file_specific_info(); 294 295 // Get drive WebApps that can accept this file. We just need to extract the 296 // doc icon for the drive app, which is set as default. 297 std::vector<drive::DriveAppInfo> drive_apps; 298 app_registry->GetAppsForFile(file_path_.Extension(), 299 file_specific_info.content_mime_type(), 300 &drive_apps); 301 if (!drive_apps.empty()) { 302 std::string default_task_id = 303 file_manager::file_tasks::GetDefaultTaskIdFromPrefs( 304 *file_owner_profile_->GetPrefs(), 305 file_specific_info.content_mime_type(), 306 file_path_.Extension()); 307 file_manager::file_tasks::TaskDescriptor default_task; 308 file_manager::file_tasks::ParseTaskID(default_task_id, &default_task); 309 DCHECK(default_task_id.empty() || !default_task.app_id.empty()); 310 for (size_t i = 0; i < drive_apps.size(); ++i) { 311 const drive::DriveAppInfo& app_info = drive_apps[i]; 312 if (default_task.app_id == app_info.app_id) { 313 // The drive app is set as default. Files.app should use the doc icon. 314 const GURL doc_icon = drive::util::FindPreferredIcon( 315 app_info.document_icons, drive::util::kPreferredIconSize); 316 properties_->custom_icon_url.reset(new std::string(doc_icon.spec())); 317 } 318 } 319 } 320 321 CompleteGetFileProperties(drive::FILE_ERROR_OK); 322 } 323 324 void CompleteGetFileProperties(drive::FileError error) { 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 326 DCHECK(!callback_.is_null()); 327 callback_.Run(error); 328 329 delete this; 330 } 331 }; // class SingleDriveEntryPropertiesGetter 332 333 } // namespace 334 335 FileBrowserPrivateGetDriveEntryPropertiesFunction:: 336 FileBrowserPrivateGetDriveEntryPropertiesFunction() 337 : processed_count_(0) {} 338 339 FileBrowserPrivateGetDriveEntryPropertiesFunction:: 340 ~FileBrowserPrivateGetDriveEntryPropertiesFunction() {} 341 342 bool FileBrowserPrivateGetDriveEntryPropertiesFunction::RunAsync() { 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 344 345 using api::file_browser_private::GetDriveEntryProperties::Params; 346 const scoped_ptr<Params> params(Params::Create(*args_)); 347 EXTENSION_FUNCTION_VALIDATE(params); 348 349 properties_list_.resize(params->file_urls.size()); 350 351 for (size_t i = 0; i < params->file_urls.size(); i++) { 352 const GURL url = GURL(params->file_urls[i]); 353 const base::FilePath local_path = file_manager::util::GetLocalPathFromURL( 354 render_view_host(), GetProfile(), url); 355 properties_list_[i] = make_linked_ptr(new DriveEntryProperties); 356 357 SingleDriveEntryPropertiesGetter::Start( 358 local_path, 359 properties_list_[i], 360 GetProfile(), 361 base::Bind(&FileBrowserPrivateGetDriveEntryPropertiesFunction:: 362 CompleteGetFileProperties, 363 this)); 364 } 365 366 return true; 367 } 368 369 void FileBrowserPrivateGetDriveEntryPropertiesFunction:: 370 CompleteGetFileProperties(drive::FileError error) { 371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 372 DCHECK(0 <= processed_count_ && processed_count_ < properties_list_.size()); 373 374 processed_count_++; 375 if (processed_count_ < properties_list_.size()) 376 return; 377 378 results_ = extensions::api::file_browser_private::GetDriveEntryProperties:: 379 Results::Create(properties_list_); 380 SendResponse(true); 381 } 382 383 bool FileBrowserPrivatePinDriveFileFunction::RunAsync() { 384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 385 386 using extensions::api::file_browser_private::PinDriveFile::Params; 387 const scoped_ptr<Params> params(Params::Create(*args_)); 388 EXTENSION_FUNCTION_VALIDATE(params); 389 390 drive::FileSystemInterface* const file_system = 391 drive::util::GetFileSystemByProfile(GetProfile()); 392 if (!file_system) // |file_system| is NULL if Drive is disabled. 393 return false; 394 395 const base::FilePath drive_path = 396 drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL( 397 render_view_host(), GetProfile(), GURL(params->file_url))); 398 if (params->pin) { 399 file_system->Pin(drive_path, 400 base::Bind(&FileBrowserPrivatePinDriveFileFunction:: 401 OnPinStateSet, this)); 402 } else { 403 file_system->Unpin(drive_path, 404 base::Bind(&FileBrowserPrivatePinDriveFileFunction:: 405 OnPinStateSet, this)); 406 } 407 return true; 408 } 409 410 void FileBrowserPrivatePinDriveFileFunction:: 411 OnPinStateSet(drive::FileError error) { 412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 413 414 if (error == drive::FILE_ERROR_OK) { 415 SendResponse(true); 416 } else { 417 SetError(drive::FileErrorToString(error)); 418 SendResponse(false); 419 } 420 } 421 422 FileBrowserPrivateGetDriveFilesFunction:: 423 FileBrowserPrivateGetDriveFilesFunction() { 424 } 425 426 FileBrowserPrivateGetDriveFilesFunction:: 427 ~FileBrowserPrivateGetDriveFilesFunction() { 428 } 429 430 bool FileBrowserPrivateGetDriveFilesFunction::RunAsync() { 431 using extensions::api::file_browser_private::GetDriveFiles::Params; 432 const scoped_ptr<Params> params(Params::Create(*args_)); 433 EXTENSION_FUNCTION_VALIDATE(params); 434 435 // Convert the list of strings to a list of GURLs. 436 for (size_t i = 0; i < params->file_urls.size(); ++i) { 437 const base::FilePath path = file_manager::util::GetLocalPathFromURL( 438 render_view_host(), GetProfile(), GURL(params->file_urls[i])); 439 DCHECK(drive::util::IsUnderDriveMountPoint(path)); 440 base::FilePath drive_path = drive::util::ExtractDrivePath(path); 441 remaining_drive_paths_.push(drive_path); 442 } 443 444 GetFileOrSendResponse(); 445 return true; 446 } 447 448 void FileBrowserPrivateGetDriveFilesFunction::GetFileOrSendResponse() { 449 // Send the response if all files are obtained. 450 if (remaining_drive_paths_.empty()) { 451 results_ = extensions::api::file_browser_private:: 452 GetDriveFiles::Results::Create(local_paths_); 453 SendResponse(true); 454 return; 455 } 456 457 // Get the file on the top of the queue. 458 base::FilePath drive_path = remaining_drive_paths_.front(); 459 460 drive::FileSystemInterface* file_system = 461 drive::util::GetFileSystemByProfile(GetProfile()); 462 if (!file_system) { 463 // |file_system| is NULL if Drive is disabled or not mounted. 464 OnFileReady(drive::FILE_ERROR_FAILED, drive_path, 465 scoped_ptr<drive::ResourceEntry>()); 466 return; 467 } 468 469 file_system->GetFile( 470 drive_path, 471 base::Bind(&FileBrowserPrivateGetDriveFilesFunction::OnFileReady, this)); 472 } 473 474 475 void FileBrowserPrivateGetDriveFilesFunction::OnFileReady( 476 drive::FileError error, 477 const base::FilePath& local_path, 478 scoped_ptr<drive::ResourceEntry> entry) { 479 base::FilePath drive_path = remaining_drive_paths_.front(); 480 481 if (error == drive::FILE_ERROR_OK) { 482 local_paths_.push_back(local_path.AsUTF8Unsafe()); 483 DVLOG(1) << "Got " << drive_path.value() << " as " << local_path.value(); 484 } else { 485 local_paths_.push_back(""); 486 DVLOG(1) << "Failed to get " << drive_path.value() 487 << " with error code: " << error; 488 } 489 490 remaining_drive_paths_.pop(); 491 492 // Start getting the next file. 493 GetFileOrSendResponse(); 494 } 495 496 bool FileBrowserPrivateCancelFileTransfersFunction::RunAsync() { 497 using extensions::api::file_browser_private::CancelFileTransfers::Params; 498 const scoped_ptr<Params> params(Params::Create(*args_)); 499 EXTENSION_FUNCTION_VALIDATE(params); 500 501 drive::DriveIntegrationService* integration_service = 502 drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile()); 503 if (!integration_service || !integration_service->IsMounted()) 504 return false; 505 506 // Create the mapping from file path to job ID. 507 drive::JobListInterface* job_list = integration_service->job_list(); 508 DCHECK(job_list); 509 std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList(); 510 511 typedef std::map<base::FilePath, std::vector<drive::JobID> > PathToIdMap; 512 PathToIdMap path_to_id_map; 513 for (size_t i = 0; i < jobs.size(); ++i) { 514 if (drive::IsActiveFileTransferJobInfo(jobs[i])) 515 path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id); 516 } 517 518 // Cancel by Job ID. 519 std::vector<linked_ptr<api::file_browser_private:: 520 FileTransferCancelStatus> > responses; 521 for (size_t i = 0; i < params->file_urls.size(); ++i) { 522 base::FilePath file_path = file_manager::util::GetLocalPathFromURL( 523 render_view_host(), GetProfile(), GURL(params->file_urls[i])); 524 if (file_path.empty()) 525 continue; 526 527 DCHECK(drive::util::IsUnderDriveMountPoint(file_path)); 528 file_path = drive::util::ExtractDrivePath(file_path); 529 530 // Cancel all the jobs for the file. 531 PathToIdMap::iterator it = path_to_id_map.find(file_path); 532 if (it != path_to_id_map.end()) { 533 for (size_t i = 0; i < it->second.size(); ++i) 534 job_list->CancelJob(it->second[i]); 535 } 536 linked_ptr<api::file_browser_private::FileTransferCancelStatus> result( 537 new api::file_browser_private::FileTransferCancelStatus); 538 result->canceled = it != path_to_id_map.end(); 539 // TODO(kinaba): simplify cancelFileTransfer() to take single URL each time, 540 // and eliminate this field; it is just returning a copy of the argument. 541 result->file_url = params->file_urls[i]; 542 responses.push_back(result); 543 } 544 results_ = api::file_browser_private::CancelFileTransfers::Results::Create( 545 responses); 546 SendResponse(true); 547 return true; 548 } 549 550 bool FileBrowserPrivateSearchDriveFunction::RunAsync() { 551 using extensions::api::file_browser_private::SearchDrive::Params; 552 const scoped_ptr<Params> params(Params::Create(*args_)); 553 EXTENSION_FUNCTION_VALIDATE(params); 554 555 drive::FileSystemInterface* const file_system = 556 drive::util::GetFileSystemByProfile(GetProfile()); 557 if (!file_system) { 558 // |file_system| is NULL if Drive is disabled. 559 return false; 560 } 561 562 file_system->Search( 563 params->search_params.query, GURL(params->search_params.next_feed), 564 base::Bind(&FileBrowserPrivateSearchDriveFunction::OnSearch, this)); 565 return true; 566 } 567 568 void FileBrowserPrivateSearchDriveFunction::OnSearch( 569 drive::FileError error, 570 const GURL& next_link, 571 scoped_ptr<SearchResultInfoList> results) { 572 if (error != drive::FILE_ERROR_OK) { 573 SendResponse(false); 574 return; 575 } 576 577 // Outlives the following conversion, since the pointer is bound to the 578 // callback. 579 DCHECK(results.get()); 580 const SearchResultInfoList& results_ref = *results.get(); 581 582 ConvertSearchResultInfoListToEntryDefinitionList( 583 GetProfile(), 584 extension_->id(), 585 results_ref, 586 base::Bind(&FileBrowserPrivateSearchDriveFunction::OnEntryDefinitionList, 587 this, 588 next_link, 589 base::Passed(&results))); 590 } 591 592 void FileBrowserPrivateSearchDriveFunction::OnEntryDefinitionList( 593 const GURL& next_link, 594 scoped_ptr<SearchResultInfoList> search_result_info_list, 595 scoped_ptr<EntryDefinitionList> entry_definition_list) { 596 DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size()); 597 base::ListValue* entries = new base::ListValue(); 598 599 // Convert Drive files to something File API stack can understand. 600 for (EntryDefinitionList::const_iterator it = entry_definition_list->begin(); 601 it != entry_definition_list->end(); 602 ++it) { 603 base::DictionaryValue* entry = new base::DictionaryValue(); 604 entry->SetString("fileSystemName", it->file_system_name); 605 entry->SetString("fileSystemRoot", it->file_system_root_url); 606 entry->SetString("fileFullPath", "/" + it->full_path.AsUTF8Unsafe()); 607 entry->SetBoolean("fileIsDirectory", it->is_directory); 608 entries->Append(entry); 609 } 610 611 base::DictionaryValue* result = new base::DictionaryValue(); 612 result->Set("entries", entries); 613 result->SetString("nextFeed", next_link.spec()); 614 615 SetResult(result); 616 SendResponse(true); 617 } 618 619 bool FileBrowserPrivateSearchDriveMetadataFunction::RunAsync() { 620 using api::file_browser_private::SearchDriveMetadata::Params; 621 const scoped_ptr<Params> params(Params::Create(*args_)); 622 EXTENSION_FUNCTION_VALIDATE(params); 623 624 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 625 if (logger) { 626 logger->Log(logging::LOG_INFO, 627 "%s[%d] called. (types: '%s', maxResults: '%d')", 628 name().c_str(), 629 request_id(), 630 api::file_browser_private::ToString( 631 params->search_params.types).c_str(), 632 params->search_params.max_results); 633 } 634 set_log_on_completion(true); 635 636 drive::FileSystemInterface* const file_system = 637 drive::util::GetFileSystemByProfile(GetProfile()); 638 if (!file_system) { 639 // |file_system| is NULL if Drive is disabled. 640 return false; 641 } 642 643 int options = -1; 644 switch (params->search_params.types) { 645 case api::file_browser_private::SEARCH_TYPE_EXCLUDE_DIRECTORIES: 646 options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES; 647 break; 648 case api::file_browser_private::SEARCH_TYPE_SHARED_WITH_ME: 649 options = drive::SEARCH_METADATA_SHARED_WITH_ME; 650 break; 651 case api::file_browser_private::SEARCH_TYPE_OFFLINE: 652 options = drive::SEARCH_METADATA_OFFLINE; 653 break; 654 case api::file_browser_private::SEARCH_TYPE_ALL: 655 options = drive::SEARCH_METADATA_ALL; 656 break; 657 case api::file_browser_private::SEARCH_TYPE_NONE: 658 break; 659 } 660 DCHECK_NE(options, -1); 661 662 file_system->SearchMetadata( 663 params->search_params.query, 664 options, 665 params->search_params.max_results, 666 base::Bind(&FileBrowserPrivateSearchDriveMetadataFunction:: 667 OnSearchMetadata, this)); 668 return true; 669 } 670 671 void FileBrowserPrivateSearchDriveMetadataFunction::OnSearchMetadata( 672 drive::FileError error, 673 scoped_ptr<drive::MetadataSearchResultVector> results) { 674 if (error != drive::FILE_ERROR_OK) { 675 SendResponse(false); 676 return; 677 } 678 679 // Outlives the following conversion, since the pointer is bound to the 680 // callback. 681 DCHECK(results.get()); 682 const drive::MetadataSearchResultVector& results_ref = *results.get(); 683 684 ConvertSearchResultInfoListToEntryDefinitionList( 685 GetProfile(), 686 extension_->id(), 687 results_ref, 688 base::Bind( 689 &FileBrowserPrivateSearchDriveMetadataFunction::OnEntryDefinitionList, 690 this, 691 base::Passed(&results))); 692 } 693 694 void FileBrowserPrivateSearchDriveMetadataFunction::OnEntryDefinitionList( 695 scoped_ptr<drive::MetadataSearchResultVector> search_result_info_list, 696 scoped_ptr<EntryDefinitionList> entry_definition_list) { 697 DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size()); 698 base::ListValue* results_list = new base::ListValue(); 699 700 // Convert Drive files to something File API stack can understand. See 701 // file_browser_handler_custom_bindings.cc and 702 // file_browser_private_custom_bindings.js for how this is magically 703 // converted to a FileEntry. 704 for (size_t i = 0; i < entry_definition_list->size(); ++i) { 705 base::DictionaryValue* result_dict = new base::DictionaryValue(); 706 707 // FileEntry fields. 708 base::DictionaryValue* entry = new base::DictionaryValue(); 709 entry->SetString( 710 "fileSystemName", entry_definition_list->at(i).file_system_name); 711 entry->SetString( 712 "fileSystemRoot", entry_definition_list->at(i).file_system_root_url); 713 entry->SetString( 714 "fileFullPath", 715 "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe()); 716 entry->SetBoolean("fileIsDirectory", 717 entry_definition_list->at(i).is_directory); 718 719 result_dict->Set("entry", entry); 720 result_dict->SetString( 721 "highlightedBaseName", 722 search_result_info_list->at(i).highlighted_base_name); 723 results_list->Append(result_dict); 724 } 725 726 SetResult(results_list); 727 SendResponse(true); 728 } 729 730 bool FileBrowserPrivateGetDriveConnectionStateFunction::RunSync() { 731 api::file_browser_private::DriveConnectionState result; 732 733 switch (drive::util::GetDriveConnectionStatus(GetProfile())) { 734 case drive::util::DRIVE_DISCONNECTED_NOSERVICE: 735 result.type = kDriveConnectionTypeOffline; 736 result.reason.reset(new std::string(kDriveConnectionReasonNoService)); 737 break; 738 case drive::util::DRIVE_DISCONNECTED_NONETWORK: 739 result.type = kDriveConnectionTypeOffline; 740 result.reason.reset(new std::string(kDriveConnectionReasonNoNetwork)); 741 break; 742 case drive::util::DRIVE_DISCONNECTED_NOTREADY: 743 result.type = kDriveConnectionTypeOffline; 744 result.reason.reset(new std::string(kDriveConnectionReasonNotReady)); 745 break; 746 case drive::util::DRIVE_CONNECTED_METERED: 747 result.type = kDriveConnectionTypeMetered; 748 break; 749 case drive::util::DRIVE_CONNECTED: 750 result.type = kDriveConnectionTypeOnline; 751 break; 752 } 753 754 results_ = api::file_browser_private::GetDriveConnectionState::Results:: 755 Create(result); 756 757 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 758 if (logger) 759 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str()); 760 return true; 761 } 762 763 bool FileBrowserPrivateRequestAccessTokenFunction::RunAsync() { 764 using extensions::api::file_browser_private::RequestAccessToken::Params; 765 const scoped_ptr<Params> params(Params::Create(*args_)); 766 EXTENSION_FUNCTION_VALIDATE(params); 767 768 drive::DriveServiceInterface* const drive_service = 769 drive::util::GetDriveServiceByProfile(GetProfile()); 770 771 if (!drive_service) { 772 // DriveService is not available. 773 SetResult(new base::StringValue("")); 774 SendResponse(true); 775 return true; 776 } 777 778 // If refreshing is requested, then clear the token to refetch it. 779 if (params->refresh) 780 drive_service->ClearAccessToken(); 781 782 // Retrieve the cached auth token (if available), otherwise the AuthService 783 // instance will try to refetch it. 784 drive_service->RequestAccessToken( 785 base::Bind(&FileBrowserPrivateRequestAccessTokenFunction:: 786 OnAccessTokenFetched, this)); 787 return true; 788 } 789 790 void FileBrowserPrivateRequestAccessTokenFunction::OnAccessTokenFetched( 791 google_apis::GDataErrorCode code, 792 const std::string& access_token) { 793 SetResult(new base::StringValue(access_token)); 794 SendResponse(true); 795 } 796 797 bool FileBrowserPrivateGetShareUrlFunction::RunAsync() { 798 using extensions::api::file_browser_private::GetShareUrl::Params; 799 const scoped_ptr<Params> params(Params::Create(*args_)); 800 EXTENSION_FUNCTION_VALIDATE(params); 801 802 const base::FilePath path = file_manager::util::GetLocalPathFromURL( 803 render_view_host(), GetProfile(), GURL(params->url)); 804 DCHECK(drive::util::IsUnderDriveMountPoint(path)); 805 806 const base::FilePath drive_path = drive::util::ExtractDrivePath(path); 807 808 drive::FileSystemInterface* const file_system = 809 drive::util::GetFileSystemByProfile(GetProfile()); 810 if (!file_system) { 811 // |file_system| is NULL if Drive is disabled. 812 return false; 813 } 814 815 file_system->GetShareUrl( 816 drive_path, 817 file_manager::util::GetFileManagerBaseUrl(), // embed origin 818 base::Bind(&FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl, this)); 819 return true; 820 } 821 822 void FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl( 823 drive::FileError error, 824 const GURL& share_url) { 825 if (error != drive::FILE_ERROR_OK) { 826 SetError("Share Url for this item is not available."); 827 SendResponse(false); 828 return; 829 } 830 831 SetResult(new base::StringValue(share_url.spec())); 832 SendResponse(true); 833 } 834 835 bool FileBrowserPrivateRequestDriveShareFunction::RunAsync() { 836 using extensions::api::file_browser_private::RequestDriveShare::Params; 837 const scoped_ptr<Params> params(Params::Create(*args_)); 838 EXTENSION_FUNCTION_VALIDATE(params); 839 840 const base::FilePath path = file_manager::util::GetLocalPathFromURL( 841 render_view_host(), GetProfile(), GURL(params->url)); 842 const base::FilePath drive_path = drive::util::ExtractDrivePath(path); 843 Profile* const owner_profile = drive::util::ExtractProfileFromPath(path); 844 845 if (!owner_profile) 846 return false; 847 848 drive::FileSystemInterface* const owner_file_system = 849 drive::util::GetFileSystemByProfile(owner_profile); 850 if (!owner_file_system) 851 return false; 852 853 const chromeos::User* const user = 854 chromeos::UserManager::Get()->GetUserByProfile(GetProfile()); 855 if (!user || !user->is_logged_in()) 856 return false; 857 858 google_apis::drive::PermissionRole role = 859 google_apis::drive::PERMISSION_ROLE_READER; 860 switch (params->share_type) { 861 case api::file_browser_private::DRIVE_SHARE_TYPE_NONE: 862 NOTREACHED(); 863 return false; 864 case api::file_browser_private::DRIVE_SHARE_TYPE_CAN_EDIT: 865 role = google_apis::drive::PERMISSION_ROLE_WRITER; 866 break; 867 case api::file_browser_private::DRIVE_SHARE_TYPE_CAN_COMMENT: 868 role = google_apis::drive::PERMISSION_ROLE_COMMENTER; 869 break; 870 case api::file_browser_private::DRIVE_SHARE_TYPE_CAN_VIEW: 871 role = google_apis::drive::PERMISSION_ROLE_READER; 872 break; 873 } 874 875 // Share |drive_path| in |owner_file_system| to |user->email()|. 876 owner_file_system->AddPermission( 877 drive_path, 878 user->email(), 879 role, 880 base::Bind(&FileBrowserPrivateRequestDriveShareFunction::OnAddPermission, 881 this)); 882 return true; 883 } 884 885 void FileBrowserPrivateRequestDriveShareFunction::OnAddPermission( 886 drive::FileError error) { 887 SendResponse(error == drive::FILE_ERROR_OK); 888 } 889 890 } // namespace extensions 891