// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/extensions/file_manager/private_api_drive.h" #include #include #include #include "base/command_line.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/drive/drive_integration_service.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" #include "chrome/browser/chromeos/file_manager/file_tasks.h" #include "chrome/browser/chromeos/file_manager/fileapi_util.h" #include "chrome/browser/chromeos/file_manager/url_util.h" #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/browser/chromeos/fileapi/external_file_url_util.h" #include "chrome/browser/chromeos/fileapi/file_system_backend.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/common/extensions/api/file_manager_private_internal.h" #include "chromeos/chromeos_switches.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_state_handler.h" #include "components/drive/drive_app_registry.h" #include "components/drive/event_logger.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/browser_thread.h" #include "google_apis/drive/auth_service.h" #include "google_apis/drive/drive_api_url_generator.h" #include "storage/common/fileapi/file_system_info.h" #include "storage/common/fileapi/file_system_util.h" #include "url/gurl.h" using content::BrowserThread; using chromeos::file_system_provider::EntryMetadata; using chromeos::file_system_provider::ProvidedFileSystemInterface; using chromeos::file_system_provider::util::FileSystemURLParser; using extensions::api::file_manager_private::EntryProperties; using extensions::api::file_manager_private::EntryPropertyName; using file_manager::util::EntryDefinition; using file_manager::util::EntryDefinitionCallback; using file_manager::util::EntryDefinitionList; using file_manager::util::EntryDefinitionListCallback; using file_manager::util::FileDefinition; using file_manager::util::FileDefinitionList; using google_apis::DriveApiUrlGenerator; namespace extensions { namespace { // List of connection types of drive. // Keep this in sync with the DriveConnectionType in common/js/util.js. const char kDriveConnectionTypeOffline[] = "offline"; const char kDriveConnectionTypeMetered[] = "metered"; const char kDriveConnectionTypeOnline[] = "online"; // List of reasons of kDriveConnectionType*. // Keep this in sync with the DriveConnectionReason in common/js/util.js. const char kDriveConnectionReasonNotReady[] = "not_ready"; const char kDriveConnectionReasonNoNetwork[] = "no_network"; const char kDriveConnectionReasonNoService[] = "no_service"; // Maximum dimension of thumbnail in file manager. File manager shows 180x180 // thumbnail. Given that we support hdpi devices, maximum dimension is 360. const int kFileManagerMaximumThumbnailDimension = 360; // Copies properties from |entry_proto| to |properties|. |shared_with_me| is // given from the running profile. void FillEntryPropertiesValueForDrive(const drive::ResourceEntry& entry_proto, bool shared_with_me, EntryProperties* properties) { properties->shared_with_me.reset(new bool(shared_with_me)); properties->shared.reset(new bool(entry_proto.shared())); const drive::PlatformFileInfoProto& file_info = entry_proto.file_info(); properties->size.reset(new double(file_info.size())); properties->modification_time.reset(new double( base::Time::FromInternalValue(file_info.last_modified()).ToJsTime())); if (!entry_proto.has_file_specific_info()) return; const drive::FileSpecificInfo& file_specific_info = entry_proto.file_specific_info(); if (!entry_proto.resource_id().empty()) { DriveApiUrlGenerator url_generator( (GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)), (GURL( google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction)), (GURL(google_apis::DriveApiUrlGenerator:: kBaseThumbnailUrlForProduction))); properties->thumbnail_url.reset(new std::string( url_generator.GetThumbnailUrl(entry_proto.resource_id(), 500 /* width */, 500 /* height */, false /* not cropped */).spec())); properties->cropped_thumbnail_url.reset(new std::string( url_generator.GetThumbnailUrl( entry_proto.resource_id(), kFileManagerMaximumThumbnailDimension /* width */, kFileManagerMaximumThumbnailDimension /* height */, true /* cropped */).spec())); } if (file_specific_info.has_image_width()) { properties->image_width.reset( new int(file_specific_info.image_width())); } if (file_specific_info.has_image_height()) { properties->image_height.reset( new int(file_specific_info.image_height())); } if (file_specific_info.has_image_rotation()) { properties->image_rotation.reset( new int(file_specific_info.image_rotation())); } properties->hosted.reset(new bool(file_specific_info.is_hosted_document())); properties->content_mime_type.reset( new std::string(file_specific_info.content_mime_type())); properties->pinned.reset( new bool(file_specific_info.cache_state().is_pinned())); properties->dirty.reset( new bool(file_specific_info.cache_state().is_dirty())); properties->present.reset( new bool(file_specific_info.cache_state().is_present())); if (file_specific_info.cache_state().is_present()) { properties->available_offline.reset(new bool(true)); } else if (file_specific_info.is_hosted_document() && file_specific_info.has_document_extension()) { const std::string file_extension = file_specific_info.document_extension(); // What's available offline? See the 'Web' column at: // https://support.google.com/drive/answer/1628467 properties->available_offline.reset( new bool(file_extension == ".gdoc" || file_extension == ".gdraw" || file_extension == ".gsheet" || file_extension == ".gslides")); } else { properties->available_offline.reset(new bool(false)); } properties->available_when_metered.reset( new bool(file_specific_info.cache_state().is_present() || file_specific_info.is_hosted_document())); } // Creates entry definition list for (metadata) search result info list. template void ConvertSearchResultInfoListToEntryDefinitionList( Profile* profile, const std::string& extension_id, const std::vector& search_result_info_list, const EntryDefinitionListCallback& callback) { FileDefinitionList file_definition_list; for (size_t i = 0; i < search_result_info_list.size(); ++i) { FileDefinition file_definition; file_definition.virtual_path = file_manager::util::ConvertDrivePathToRelativeFileSystemPath( profile, extension_id, search_result_info_list.at(i).path); file_definition.is_directory = search_result_info_list.at(i).is_directory; file_definition_list.push_back(file_definition); } file_manager::util::ConvertFileDefinitionListToEntryDefinitionList( profile, extension_id, file_definition_list, // Safe, since copied internally. callback); } class SingleEntryPropertiesGetterForDrive { public: typedef base::Callback properties, base::File::Error error)> ResultCallback; // Creates an instance and starts the process. static void Start(const base::FilePath local_path, const std::set& names, Profile* const profile, const ResultCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); SingleEntryPropertiesGetterForDrive* instance = new SingleEntryPropertiesGetterForDrive(local_path, names, profile, callback); instance->StartProcess(); // The instance will be destroyed by itself. } virtual ~SingleEntryPropertiesGetterForDrive() {} private: SingleEntryPropertiesGetterForDrive( const base::FilePath local_path, const std::set& /* names */, Profile* const profile, const ResultCallback& callback) : callback_(callback), local_path_(local_path), running_profile_(profile), properties_(new EntryProperties), file_owner_profile_(NULL), weak_ptr_factory_(this) { DCHECK(!callback_.is_null()); DCHECK(profile); } void StartProcess() { DCHECK_CURRENTLY_ON(BrowserThread::UI); file_path_ = drive::util::ExtractDrivePath(local_path_); file_owner_profile_ = drive::util::ExtractProfileFromPath(local_path_); if (!file_owner_profile_ || !g_browser_process->profile_manager()->IsValidProfile( file_owner_profile_)) { CompleteGetEntryProperties(drive::FILE_ERROR_FAILED); return; } // Start getting the file info. drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(file_owner_profile_); if (!file_system) { // |file_system| is NULL if Drive is disabled or not mounted. CompleteGetEntryProperties(drive::FILE_ERROR_FAILED); return; } file_system->GetResourceEntry( file_path_, base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetFileInfo, weak_ptr_factory_.GetWeakPtr())); } void OnGetFileInfo(drive::FileError error, scoped_ptr entry) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (error != drive::FILE_ERROR_OK) { CompleteGetEntryProperties(error); return; } DCHECK(entry); owner_resource_entry_.swap(entry); if (running_profile_->IsSameProfile(file_owner_profile_)) { StartParseFileInfo(owner_resource_entry_->shared_with_me()); return; } // If the running profile does not own the file, obtain the shared_with_me // flag from the running profile's value. drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(running_profile_); if (!file_system) { CompleteGetEntryProperties(drive::FILE_ERROR_FAILED); return; } file_system->GetPathFromResourceId( owner_resource_entry_->resource_id(), base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetRunningPath, weak_ptr_factory_.GetWeakPtr())); } void OnGetRunningPath(drive::FileError error, const base::FilePath& file_path) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (error != drive::FILE_ERROR_OK) { // The running profile does not know the file. StartParseFileInfo(false); return; } drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(running_profile_); if (!file_system) { // The drive is disable for the running profile. StartParseFileInfo(false); return; } file_system->GetResourceEntry( file_path, base::Bind(&SingleEntryPropertiesGetterForDrive::OnGetShareInfo, weak_ptr_factory_.GetWeakPtr())); } void OnGetShareInfo(drive::FileError error, scoped_ptr entry) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (error != drive::FILE_ERROR_OK) { CompleteGetEntryProperties(error); return; } DCHECK(entry.get()); StartParseFileInfo(entry->shared_with_me()); } void StartParseFileInfo(bool shared_with_me) { DCHECK_CURRENTLY_ON(BrowserThread::UI); FillEntryPropertiesValueForDrive( *owner_resource_entry_, shared_with_me, properties_.get()); drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(file_owner_profile_); drive::DriveAppRegistry* const app_registry = drive::util::GetDriveAppRegistryByProfile(file_owner_profile_); if (!file_system || !app_registry) { // |file_system| or |app_registry| is NULL if Drive is disabled. CompleteGetEntryProperties(drive::FILE_ERROR_FAILED); return; } // The properties meaningful for directories are already filled in // FillEntryPropertiesValueForDrive(). if (!owner_resource_entry_->has_file_specific_info()) { CompleteGetEntryProperties(drive::FILE_ERROR_OK); return; } const drive::FileSpecificInfo& file_specific_info = owner_resource_entry_->file_specific_info(); // Get drive WebApps that can accept this file. We just need to extract the // doc icon for the drive app, which is set as default. std::vector drive_apps; app_registry->GetAppsForFile(file_path_.Extension(), file_specific_info.content_mime_type(), &drive_apps); if (!drive_apps.empty()) { std::string default_task_id = file_manager::file_tasks::GetDefaultTaskIdFromPrefs( *file_owner_profile_->GetPrefs(), file_specific_info.content_mime_type(), file_path_.Extension()); file_manager::file_tasks::TaskDescriptor default_task; file_manager::file_tasks::ParseTaskID(default_task_id, &default_task); DCHECK(default_task_id.empty() || !default_task.app_id.empty()); for (size_t i = 0; i < drive_apps.size(); ++i) { const drive::DriveAppInfo& app_info = drive_apps[i]; if (default_task.app_id == app_info.app_id) { // The drive app is set as default. Files.app should use the doc icon. const GURL doc_icon = drive::util::FindPreferredIcon( app_info.document_icons, drive::util::kPreferredIconSize); properties_->custom_icon_url.reset(new std::string(doc_icon.spec())); } } } CompleteGetEntryProperties(drive::FILE_ERROR_OK); } void CompleteGetEntryProperties(drive::FileError error) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!callback_.is_null()); callback_.Run(std::move(properties_), drive::FileErrorToBaseFileError(error)); BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); } // Given parameters. const ResultCallback callback_; const base::FilePath local_path_; Profile* const running_profile_; // Values used in the process. scoped_ptr properties_; Profile* file_owner_profile_; base::FilePath file_path_; scoped_ptr owner_resource_entry_; base::WeakPtrFactory weak_ptr_factory_; }; // class SingleEntryPropertiesGetterForDrive class SingleEntryPropertiesGetterForFileSystemProvider { public: typedef base::Callback properties, base::File::Error error)> ResultCallback; // Creates an instance and starts the process. static void Start(const storage::FileSystemURL file_system_url, const std::set& names, const ResultCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); SingleEntryPropertiesGetterForFileSystemProvider* instance = new SingleEntryPropertiesGetterForFileSystemProvider(file_system_url, names, callback); instance->StartProcess(); // The instance will be destroyed by itself. } virtual ~SingleEntryPropertiesGetterForFileSystemProvider() {} private: SingleEntryPropertiesGetterForFileSystemProvider( const storage::FileSystemURL& file_system_url, const std::set& names, const ResultCallback& callback) : callback_(callback), file_system_url_(file_system_url), names_(names), properties_(new EntryProperties), weak_ptr_factory_(this) { DCHECK(!callback_.is_null()); } void StartProcess() { DCHECK_CURRENTLY_ON(BrowserThread::UI); FileSystemURLParser parser(file_system_url_); if (!parser.Parse()) { CompleteGetEntryProperties(base::File::FILE_ERROR_NOT_FOUND); return; } ProvidedFileSystemInterface::MetadataFieldMask field_mask = ProvidedFileSystemInterface::METADATA_FIELD_NONE; if (names_.find(api::file_manager_private::ENTRY_PROPERTY_NAME_SIZE) != names_.end()) { field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_SIZE; } if (names_.find( api::file_manager_private::ENTRY_PROPERTY_NAME_MODIFICATIONTIME) != names_.end()) { field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_MODIFICATION_TIME; } if (names_.find( api::file_manager_private::ENTRY_PROPERTY_NAME_CONTENTMIMETYPE) != names_.end()) { field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_MIME_TYPE; } if (names_.find( api::file_manager_private::ENTRY_PROPERTY_NAME_THUMBNAILURL) != names_.end()) { field_mask |= ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL; } parser.file_system()->GetMetadata( parser.file_path(), field_mask, base::Bind(&SingleEntryPropertiesGetterForFileSystemProvider:: OnGetMetadataCompleted, weak_ptr_factory_.GetWeakPtr())); } void OnGetMetadataCompleted(scoped_ptr metadata, base::File::Error result) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (result != base::File::FILE_OK) { CompleteGetEntryProperties(result); return; } if (names_.find(api::file_manager_private::ENTRY_PROPERTY_NAME_SIZE) != names_.end()) { properties_->size.reset(new double(*metadata->size.get())); } if (names_.find( api::file_manager_private::ENTRY_PROPERTY_NAME_MODIFICATIONTIME) != names_.end()) { properties_->modification_time.reset( new double(metadata->modification_time->ToJsTime())); } if (names_.find( api::file_manager_private::ENTRY_PROPERTY_NAME_CONTENTMIMETYPE) != names_.end() && metadata->mime_type.get()) { properties_->content_mime_type.reset( new std::string(*metadata->mime_type)); } if (names_.find( api::file_manager_private::ENTRY_PROPERTY_NAME_THUMBNAILURL) != names_.end() && metadata->thumbnail.get()) { properties_->thumbnail_url.reset(new std::string(*metadata->thumbnail)); } CompleteGetEntryProperties(base::File::FILE_OK); } void CompleteGetEntryProperties(base::File::Error result) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!callback_.is_null()); callback_.Run(std::move(properties_), result); BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); } // Given parameters. const ResultCallback callback_; const storage::FileSystemURL file_system_url_; const std::set names_; // Values used in the process. scoped_ptr properties_; base::WeakPtrFactory weak_ptr_factory_; }; // class SingleEntryPropertiesGetterForDrive } // namespace FileManagerPrivateInternalGetEntryPropertiesFunction:: FileManagerPrivateInternalGetEntryPropertiesFunction() : processed_count_(0) { } FileManagerPrivateInternalGetEntryPropertiesFunction:: ~FileManagerPrivateInternalGetEntryPropertiesFunction() { } bool FileManagerPrivateInternalGetEntryPropertiesFunction::RunAsync() { DCHECK_CURRENTLY_ON(BrowserThread::UI); using api::file_manager_private_internal::GetEntryProperties::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); scoped_refptr file_system_context = file_manager::util::GetFileSystemContextForRenderFrameHost( GetProfile(), render_frame_host()); properties_list_.resize(params->urls.size()); const std::set names_as_set(params->names.begin(), params->names.end()); for (size_t i = 0; i < params->urls.size(); i++) { const GURL url = GURL(params->urls[i]); const storage::FileSystemURL file_system_url = file_system_context->CrackURL(url); switch (file_system_url.type()) { case storage::kFileSystemTypeDrive: SingleEntryPropertiesGetterForDrive::Start( file_system_url.path(), names_as_set, GetProfile(), base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction:: CompleteGetEntryProperties, this, i, file_system_url)); break; case storage::kFileSystemTypeProvided: SingleEntryPropertiesGetterForFileSystemProvider::Start( file_system_url, names_as_set, base::Bind(&FileManagerPrivateInternalGetEntryPropertiesFunction:: CompleteGetEntryProperties, this, i, file_system_url)); break; default: // TODO(yawano) Change this to support other voluems (e.g. local) ,and // integrate fileManagerPrivate.getMimeType to this method. LOG(ERROR) << "Not supported file system type."; CompleteGetEntryProperties(i, file_system_url, make_scoped_ptr(new EntryProperties), base::File::FILE_ERROR_INVALID_OPERATION); } } return true; } void FileManagerPrivateInternalGetEntryPropertiesFunction:: CompleteGetEntryProperties(size_t index, const storage::FileSystemURL& url, scoped_ptr properties, base::File::Error error) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(0 <= processed_count_ && processed_count_ < properties_list_.size()); properties_list_[index] = make_linked_ptr(properties.release()); if (error == base::File::FILE_OK) { properties_list_[index]->external_file_url.reset( new std::string(chromeos::FileSystemURLToExternalFileURL(url).spec())); } processed_count_++; if (processed_count_ < properties_list_.size()) return; results_ = extensions::api::file_manager_private_internal:: GetEntryProperties::Results::Create(properties_list_); SendResponse(true); } bool FileManagerPrivateInternalPinDriveFileFunction::RunAsync() { DCHECK_CURRENTLY_ON(BrowserThread::UI); using extensions::api::file_manager_private_internal::PinDriveFile::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(GetProfile()); if (!file_system) // |file_system| is NULL if Drive is disabled. return false; const base::FilePath drive_path = drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL( render_frame_host(), GetProfile(), GURL(params->url))); if (params->pin) { file_system->Pin( drive_path, base::Bind( &FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet, this)); } else { file_system->Unpin( drive_path, base::Bind( &FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet, this)); } return true; } void FileManagerPrivateInternalPinDriveFileFunction::OnPinStateSet( drive::FileError error) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (error == drive::FILE_ERROR_OK) { SendResponse(true); } else { SetError(drive::FileErrorToString(error)); SendResponse(false); } } bool FileManagerPrivateInternalCancelFileTransfersFunction::RunAsync() { using extensions::api::file_manager_private_internal::CancelFileTransfers:: Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); drive::DriveIntegrationService* integration_service = drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile()); if (!integration_service || !integration_service->IsMounted()) return false; drive::JobListInterface* const job_list = integration_service->job_list(); DCHECK(job_list); const std::vector jobs = job_list->GetJobInfoList(); // Create the mapping from file path to job ID. typedef std::map> PathToIdMap; PathToIdMap path_to_id_map; for (size_t i = 0; i < jobs.size(); ++i) { if (drive::IsActiveFileTransferJobInfo(jobs[i])) path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id); } for (size_t i = 0; i < params->urls.size(); ++i) { base::FilePath file_path = file_manager::util::GetLocalPathFromURL( render_frame_host(), GetProfile(), GURL(params->urls[i])); if (file_path.empty()) continue; file_path = drive::util::ExtractDrivePath(file_path); DCHECK(file_path.empty()); // Cancel all the jobs for the file. PathToIdMap::iterator it = path_to_id_map.find(file_path); if (it != path_to_id_map.end()) { for (size_t i = 0; i < it->second.size(); ++i) job_list->CancelJob(it->second[i]); } } SendResponse(true); return true; } bool FileManagerPrivateCancelAllFileTransfersFunction::RunAsync() { drive::DriveIntegrationService* const integration_service = drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile()); if (!integration_service || !integration_service->IsMounted()) return false; drive::JobListInterface* const job_list = integration_service->job_list(); DCHECK(job_list); const std::vector jobs = job_list->GetJobInfoList(); for (size_t i = 0; i < jobs.size(); ++i) { if (drive::IsActiveFileTransferJobInfo(jobs[i])) job_list->CancelJob(jobs[i].job_id); } SendResponse(true); return true; } bool FileManagerPrivateSearchDriveFunction::RunAsync() { using extensions::api::file_manager_private::SearchDrive::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(GetProfile()); if (!file_system) { // |file_system| is NULL if Drive is disabled. return false; } file_system->Search( params->search_params.query, GURL(params->search_params.next_feed), base::Bind(&FileManagerPrivateSearchDriveFunction::OnSearch, this)); return true; } void FileManagerPrivateSearchDriveFunction::OnSearch( drive::FileError error, const GURL& next_link, scoped_ptr results) { if (error != drive::FILE_ERROR_OK) { SendResponse(false); return; } // Outlives the following conversion, since the pointer is bound to the // callback. DCHECK(results.get()); const SearchResultInfoList& results_ref = *results.get(); ConvertSearchResultInfoListToEntryDefinitionList( GetProfile(), extension_->id(), results_ref, base::Bind(&FileManagerPrivateSearchDriveFunction::OnEntryDefinitionList, this, next_link, base::Passed(&results))); } void FileManagerPrivateSearchDriveFunction::OnEntryDefinitionList( const GURL& next_link, scoped_ptr search_result_info_list, scoped_ptr entry_definition_list) { DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size()); base::ListValue* entries = new base::ListValue(); // Convert Drive files to something File API stack can understand. for (EntryDefinitionList::const_iterator it = entry_definition_list->begin(); it != entry_definition_list->end(); ++it) { base::DictionaryValue* entry = new base::DictionaryValue(); entry->SetString("fileSystemName", it->file_system_name); entry->SetString("fileSystemRoot", it->file_system_root_url); entry->SetString("fileFullPath", "/" + it->full_path.AsUTF8Unsafe()); entry->SetBoolean("fileIsDirectory", it->is_directory); entries->Append(entry); } base::DictionaryValue* result = new base::DictionaryValue(); result->Set("entries", entries); result->SetString("nextFeed", next_link.spec()); SetResult(result); SendResponse(true); } bool FileManagerPrivateSearchDriveMetadataFunction::RunAsync() { using api::file_manager_private::SearchDriveMetadata::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); if (logger) { logger->Log(logging::LOG_INFO, "%s[%d] called. (types: '%s', maxResults: '%d')", name(), request_id(), api::file_manager_private::ToString( params->search_params.types).c_str(), params->search_params.max_results); } set_log_on_completion(true); drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(GetProfile()); if (!file_system) { // |file_system| is NULL if Drive is disabled. return false; } int options = -1; switch (params->search_params.types) { case api::file_manager_private::SEARCH_TYPE_EXCLUDE_DIRECTORIES: options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES; break; case api::file_manager_private::SEARCH_TYPE_SHARED_WITH_ME: options = drive::SEARCH_METADATA_SHARED_WITH_ME; break; case api::file_manager_private::SEARCH_TYPE_OFFLINE: options = drive::SEARCH_METADATA_OFFLINE; break; case api::file_manager_private::SEARCH_TYPE_ALL: options = drive::SEARCH_METADATA_ALL; break; case api::file_manager_private::SEARCH_TYPE_NONE: break; } DCHECK_NE(options, -1); file_system->SearchMetadata( params->search_params.query, options, params->search_params.max_results, base::Bind(&FileManagerPrivateSearchDriveMetadataFunction:: OnSearchMetadata, this)); return true; } void FileManagerPrivateSearchDriveMetadataFunction::OnSearchMetadata( drive::FileError error, scoped_ptr results) { if (error != drive::FILE_ERROR_OK) { SendResponse(false); return; } // Outlives the following conversion, since the pointer is bound to the // callback. DCHECK(results.get()); const drive::MetadataSearchResultVector& results_ref = *results.get(); ConvertSearchResultInfoListToEntryDefinitionList( GetProfile(), extension_->id(), results_ref, base::Bind( &FileManagerPrivateSearchDriveMetadataFunction::OnEntryDefinitionList, this, base::Passed(&results))); } void FileManagerPrivateSearchDriveMetadataFunction::OnEntryDefinitionList( scoped_ptr search_result_info_list, scoped_ptr entry_definition_list) { DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size()); base::ListValue* results_list = new base::ListValue(); // Convert Drive files to something File API stack can understand. See // file_browser_handler_custom_bindings.cc and // file_manager_private_custom_bindings.js for how this is magically // converted to a FileEntry. for (size_t i = 0; i < entry_definition_list->size(); ++i) { base::DictionaryValue* result_dict = new base::DictionaryValue(); // FileEntry fields. base::DictionaryValue* entry = new base::DictionaryValue(); entry->SetString( "fileSystemName", entry_definition_list->at(i).file_system_name); entry->SetString( "fileSystemRoot", entry_definition_list->at(i).file_system_root_url); entry->SetString( "fileFullPath", "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe()); entry->SetBoolean("fileIsDirectory", entry_definition_list->at(i).is_directory); result_dict->Set("entry", entry); result_dict->SetString( "highlightedBaseName", search_result_info_list->at(i).highlighted_base_name); results_list->Append(result_dict); } SetResult(results_list); SendResponse(true); } bool FileManagerPrivateGetDriveConnectionStateFunction::RunSync() { api::file_manager_private::DriveConnectionState result; switch (drive::util::GetDriveConnectionStatus(GetProfile())) { case drive::util::DRIVE_DISCONNECTED_NOSERVICE: result.type = kDriveConnectionTypeOffline; result.reason.reset(new std::string(kDriveConnectionReasonNoService)); break; case drive::util::DRIVE_DISCONNECTED_NONETWORK: result.type = kDriveConnectionTypeOffline; result.reason.reset(new std::string(kDriveConnectionReasonNoNetwork)); break; case drive::util::DRIVE_DISCONNECTED_NOTREADY: result.type = kDriveConnectionTypeOffline; result.reason.reset(new std::string(kDriveConnectionReasonNotReady)); break; case drive::util::DRIVE_CONNECTED_METERED: result.type = kDriveConnectionTypeMetered; break; case drive::util::DRIVE_CONNECTED: result.type = kDriveConnectionTypeOnline; break; } result.has_cellular_network_access = chromeos::NetworkHandler::Get() ->network_state_handler() ->FirstNetworkByType(chromeos::NetworkTypePattern::Mobile()); results_ = api::file_manager_private::GetDriveConnectionState::Results:: Create(result); drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); if (logger) logger->Log(logging::LOG_INFO, "%s succeeded.", name()); return true; } bool FileManagerPrivateRequestAccessTokenFunction::RunAsync() { using extensions::api::file_manager_private::RequestAccessToken::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); drive::DriveServiceInterface* const drive_service = drive::util::GetDriveServiceByProfile(GetProfile()); if (!drive_service) { // DriveService is not available. SetResult(new base::StringValue("")); SendResponse(true); return true; } // If refreshing is requested, then clear the token to refetch it. if (params->refresh) drive_service->ClearAccessToken(); // Retrieve the cached auth token (if available), otherwise the AuthService // instance will try to refetch it. drive_service->RequestAccessToken( base::Bind(&FileManagerPrivateRequestAccessTokenFunction:: OnAccessTokenFetched, this)); return true; } void FileManagerPrivateRequestAccessTokenFunction::OnAccessTokenFetched( google_apis::DriveApiErrorCode code, const std::string& access_token) { SetResult(new base::StringValue(access_token)); SendResponse(true); } bool FileManagerPrivateInternalGetShareUrlFunction::RunAsync() { using extensions::api::file_manager_private_internal::GetShareUrl::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); const base::FilePath path = file_manager::util::GetLocalPathFromURL( render_frame_host(), GetProfile(), GURL(params->url)); DCHECK(drive::util::IsUnderDriveMountPoint(path)); const base::FilePath drive_path = drive::util::ExtractDrivePath(path); drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(GetProfile()); if (!file_system) { // |file_system| is NULL if Drive is disabled. return false; } file_system->GetShareUrl( drive_path, GURL("chrome-extension://" + extension_id()), // embed origin base::Bind(&FileManagerPrivateInternalGetShareUrlFunction::OnGetShareUrl, this)); return true; } void FileManagerPrivateInternalGetShareUrlFunction::OnGetShareUrl( drive::FileError error, const GURL& share_url) { if (error != drive::FILE_ERROR_OK) { SetError("Share Url for this item is not available."); SendResponse(false); return; } SetResult(new base::StringValue(share_url.spec())); SendResponse(true); } bool FileManagerPrivateInternalRequestDriveShareFunction::RunAsync() { using extensions::api::file_manager_private_internal::RequestDriveShare:: Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); const base::FilePath path = file_manager::util::GetLocalPathFromURL( render_frame_host(), GetProfile(), GURL(params->url)); const base::FilePath drive_path = drive::util::ExtractDrivePath(path); Profile* const owner_profile = drive::util::ExtractProfileFromPath(path); if (!owner_profile) return false; drive::FileSystemInterface* const owner_file_system = drive::util::GetFileSystemByProfile(owner_profile); if (!owner_file_system) return false; const user_manager::User* const user = chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile()); if (!user || !user->is_logged_in()) return false; google_apis::drive::PermissionRole role = google_apis::drive::PERMISSION_ROLE_READER; switch (params->share_type) { case api::file_manager_private::DRIVE_SHARE_TYPE_NONE: NOTREACHED(); return false; case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_EDIT: role = google_apis::drive::PERMISSION_ROLE_WRITER; break; case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_COMMENT: role = google_apis::drive::PERMISSION_ROLE_COMMENTER; break; case api::file_manager_private::DRIVE_SHARE_TYPE_CAN_VIEW: role = google_apis::drive::PERMISSION_ROLE_READER; break; } // Share |drive_path| in |owner_file_system| to |user->email()|. owner_file_system->AddPermission( drive_path, user->email(), role, base::Bind( &FileManagerPrivateInternalRequestDriveShareFunction::OnAddPermission, this)); return true; } void FileManagerPrivateInternalRequestDriveShareFunction::OnAddPermission( drive::FileError error) { SendResponse(error == drive::FILE_ERROR_OK); } FileManagerPrivateInternalGetDownloadUrlFunction:: FileManagerPrivateInternalGetDownloadUrlFunction() {} FileManagerPrivateInternalGetDownloadUrlFunction:: ~FileManagerPrivateInternalGetDownloadUrlFunction() {} bool FileManagerPrivateInternalGetDownloadUrlFunction::RunAsync() { using extensions::api::file_manager_private_internal::GetShareUrl::Params; const scoped_ptr params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); // Start getting the file info. drive::FileSystemInterface* const file_system = drive::util::GetFileSystemByProfile(GetProfile()); if (!file_system) { // |file_system| is NULL if Drive is disabled or not mounted. SetError("Drive is disabled or not mounted."); SetResult(new base::StringValue("")); // Intentionally returns a blank. return false; } const base::FilePath path = file_manager::util::GetLocalPathFromURL( render_frame_host(), GetProfile(), GURL(params->url)); if (!drive::util::IsUnderDriveMountPoint(path)) { SetError("The given file is not in Drive."); SetResult(new base::StringValue("")); // Intentionally returns a blank. return false; } base::FilePath file_path = drive::util::ExtractDrivePath(path); file_system->GetResourceEntry( file_path, base::Bind( &FileManagerPrivateInternalGetDownloadUrlFunction::OnGetResourceEntry, this)); return true; } void FileManagerPrivateInternalGetDownloadUrlFunction::OnGetResourceEntry( drive::FileError error, scoped_ptr entry) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (error != drive::FILE_ERROR_OK) { SetError("Download Url for this item is not available."); SetResult(new base::StringValue("")); // Intentionally returns a blank. SendResponse(false); return; } DriveApiUrlGenerator url_generator( (GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)), (GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction)), (GURL( google_apis::DriveApiUrlGenerator::kBaseThumbnailUrlForProduction))); download_url_ = url_generator.GenerateDownloadFileUrl(entry->resource_id()); ProfileOAuth2TokenService* oauth2_token_service = ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile()); SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(GetProfile()); const std::string& account_id = signin_manager->GetAuthenticatedAccountId(); std::vector scopes; scopes.push_back("https://www.googleapis.com/auth/drive.readonly"); auth_service_.reset( new google_apis::AuthService(oauth2_token_service, account_id, GetProfile()->GetRequestContext(), scopes)); auth_service_->StartAuthentication(base::Bind( &FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched, this)); } void FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched( google_apis::DriveApiErrorCode code, const std::string& access_token) { if (code != google_apis::HTTP_SUCCESS) { SetError("Not able to fetch the token."); SetResult(new base::StringValue("")); // Intentionally returns a blank. SendResponse(false); return; } const std::string url = download_url_.Resolve("?access_token=" + access_token).spec(); SetResult(new base::StringValue(url)); SendResponse(true); } } // namespace extensions