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