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