Home | History | Annotate | Download | only in file_manager
      1 // Copyright (c) 2012 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/file_tasks.h"
      6 
      7 #include "apps/launcher.h"
      8 #include "base/bind.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "chrome/browser/chromeos/drive/file_task_executor.h"
     11 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.h"
     12 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
     13 #include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
     14 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
     15 #include "chrome/browser/extensions/extension_host.h"
     16 #include "chrome/browser/extensions/extension_service.h"
     17 #include "chrome/browser/extensions/extension_system.h"
     18 #include "chrome/browser/extensions/extension_tab_util.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/common/pref_names.h"
     21 #include "webkit/browser/fileapi/file_system_context.h"
     22 #include "webkit/browser/fileapi/file_system_url.h"
     23 
     24 using extensions::Extension;
     25 using fileapi::FileSystemURL;
     26 
     27 namespace file_manager {
     28 namespace file_tasks {
     29 
     30 // The values "file" and "app" are confusing, but cannot be changed easily as
     31 // these are used in default task IDs stored in preferences.
     32 //
     33 // TODO(satorux): We should rename them to "file_browser_handler" and
     34 // "file_handler" respectively when switching from preferences to
     35 // chrome.storage crbug.com/267359
     36 const char kFileBrowserHandlerTaskType[] = "file";
     37 const char kFileHandlerTaskType[] = "app";
     38 const char kDriveTaskType[] = "drive";
     39 
     40 namespace {
     41 
     42 // Legacy Drive task extension prefix, used by CrackTaskID.
     43 const char kDriveTaskExtensionPrefix[] = "drive-app:";
     44 const size_t kDriveTaskExtensionPrefixLength =
     45     arraysize(kDriveTaskExtensionPrefix) - 1;
     46 
     47 // Checks if the file browser extension has permissions for the files in its
     48 // file system context.
     49 bool FileBrowserHasAccessPermissionForFiles(
     50     Profile* profile,
     51     const GURL& source_url,
     52     const std::string& file_browser_id,
     53     const std::vector<FileSystemURL>& files) {
     54   fileapi::ExternalFileSystemBackend* backend =
     55       fileapi_util::GetFileSystemContextForExtensionId(
     56           profile, file_browser_id)->external_backend();
     57   if (!backend)
     58     return false;
     59 
     60   for (size_t i = 0; i < files.size(); ++i) {
     61     // Make sure this url really being used by the right caller extension.
     62     if (source_url.GetOrigin() != files[i].origin())
     63       return false;
     64 
     65     if (!chromeos::FileSystemBackend::CanHandleURL(files[i]) ||
     66         !backend->IsAccessAllowed(files[i])) {
     67       return false;
     68     }
     69   }
     70 
     71   return true;
     72 }
     73 
     74 }  // namespace
     75 
     76 void UpdateDefaultTask(Profile* profile,
     77                        const std::string& task_id,
     78                        const std::set<std::string>& suffixes,
     79                        const std::set<std::string>& mime_types) {
     80   if (!profile || !profile->GetPrefs())
     81     return;
     82 
     83   if (!mime_types.empty()) {
     84     DictionaryPrefUpdate mime_type_pref(profile->GetPrefs(),
     85                                         prefs::kDefaultTasksByMimeType);
     86     for (std::set<std::string>::const_iterator iter = mime_types.begin();
     87         iter != mime_types.end(); ++iter) {
     88       base::StringValue* value = new base::StringValue(task_id);
     89       mime_type_pref->SetWithoutPathExpansion(*iter, value);
     90     }
     91   }
     92 
     93   if (!suffixes.empty()) {
     94     DictionaryPrefUpdate mime_type_pref(profile->GetPrefs(),
     95                                         prefs::kDefaultTasksBySuffix);
     96     for (std::set<std::string>::const_iterator iter = suffixes.begin();
     97         iter != suffixes.end(); ++iter) {
     98       base::StringValue* value = new base::StringValue(task_id);
     99       // Suffixes are case insensitive.
    100       std::string lower_suffix = StringToLowerASCII(*iter);
    101       mime_type_pref->SetWithoutPathExpansion(lower_suffix, value);
    102     }
    103   }
    104 }
    105 
    106 std::string GetDefaultTaskIdFromPrefs(Profile* profile,
    107                                       const std::string& mime_type,
    108                                       const std::string& suffix) {
    109   VLOG(1) << "Looking for default for MIME type: " << mime_type
    110       << " and suffix: " << suffix;
    111   std::string task_id;
    112   if (!mime_type.empty()) {
    113     const DictionaryValue* mime_task_prefs =
    114         profile->GetPrefs()->GetDictionary(prefs::kDefaultTasksByMimeType);
    115     DCHECK(mime_task_prefs);
    116     LOG_IF(ERROR, !mime_task_prefs) << "Unable to open MIME type prefs";
    117     if (mime_task_prefs &&
    118         mime_task_prefs->GetStringWithoutPathExpansion(mime_type, &task_id)) {
    119       VLOG(1) << "Found MIME default handler: " << task_id;
    120       return task_id;
    121     }
    122   }
    123 
    124   const DictionaryValue* suffix_task_prefs =
    125       profile->GetPrefs()->GetDictionary(prefs::kDefaultTasksBySuffix);
    126   DCHECK(suffix_task_prefs);
    127   LOG_IF(ERROR, !suffix_task_prefs) << "Unable to open suffix prefs";
    128   std::string lower_suffix = StringToLowerASCII(suffix);
    129   if (suffix_task_prefs)
    130     suffix_task_prefs->GetStringWithoutPathExpansion(lower_suffix, &task_id);
    131   VLOG_IF(1, !task_id.empty()) << "Found suffix default handler: " << task_id;
    132   return task_id;
    133 }
    134 
    135 std::string MakeTaskID(const std::string& extension_id,
    136                        const std::string& task_type,
    137                        const std::string& action_id) {
    138   DCHECK(task_type == kFileBrowserHandlerTaskType ||
    139          task_type == kDriveTaskType ||
    140          task_type == kFileHandlerTaskType);
    141   return base::StringPrintf("%s|%s|%s",
    142                             extension_id.c_str(),
    143                             task_type.c_str(),
    144                             action_id.c_str());
    145 }
    146 
    147 std::string MakeDriveAppTaskId(const std::string& app_id) {
    148   return MakeTaskID(app_id, kDriveTaskType, "open-with");
    149 }
    150 
    151 bool ParseTaskID(const std::string& task_id, TaskDescriptor* task) {
    152   DCHECK(task);
    153 
    154   std::vector<std::string> result;
    155   int count = Tokenize(task_id, std::string("|"), &result);
    156 
    157   // Parse a legacy task ID that only contain two parts. Drive tasks are
    158   // identified by a prefix "drive-app:" on the extension ID. The legacy task
    159   // IDs can be stored in preferences.
    160   // TODO(satorux): We should get rid of this code: crbug.com/267359.
    161   if (count == 2) {
    162     if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
    163       task->task_type = kDriveTaskType;
    164       task->app_id = result[0].substr(kDriveTaskExtensionPrefixLength);
    165     } else {
    166       task->task_type = kFileBrowserHandlerTaskType;
    167       task->app_id = result[0];
    168     }
    169 
    170     task->action_id = result[1];
    171 
    172     return true;
    173   }
    174 
    175   if (count != 3)
    176     return false;
    177 
    178  task->app_id = result[0];
    179  task->task_type = result[1];
    180  DCHECK(task->task_type == kFileBrowserHandlerTaskType ||
    181         task->task_type == kDriveTaskType ||
    182         task->task_type == kFileHandlerTaskType);
    183  task->action_id = result[2];
    184 
    185   return true;
    186 }
    187 
    188 bool ExecuteFileTask(Profile* profile,
    189                      const GURL& source_url,
    190                      const std::string& file_browser_id,
    191                      int32 tab_id,
    192                      const TaskDescriptor& task,
    193                      const std::vector<FileSystemURL>& file_urls,
    194                      const FileTaskFinishedCallback& done) {
    195   if (!FileBrowserHasAccessPermissionForFiles(profile, source_url,
    196                                               file_browser_id, file_urls))
    197     return false;
    198 
    199   // drive::FileTaskExecutor is responsible to handle drive tasks.
    200   if (task.task_type == kDriveTaskType) {
    201     DCHECK_EQ("open-with", task.action_id);
    202     drive::FileTaskExecutor* executor =
    203         new drive::FileTaskExecutor(profile, task.app_id);
    204     executor->Execute(file_urls, done);
    205     return true;
    206   }
    207 
    208   // Get the extension.
    209   ExtensionService* service =
    210       extensions::ExtensionSystem::Get(profile)->extension_service();
    211   const Extension* extension = service ?
    212       service->GetExtensionById(task.app_id, false) : NULL;
    213   if (!extension)
    214     return false;
    215 
    216   // Execute the task.
    217   if (task.task_type == kFileBrowserHandlerTaskType) {
    218     return file_browser_handlers::ExecuteFileBrowserHandler(
    219         profile,
    220         extension,
    221         tab_id,
    222         task.action_id,
    223         file_urls,
    224         done);
    225   } else if (task.task_type == kFileHandlerTaskType) {
    226     for (size_t i = 0; i != file_urls.size(); ++i) {
    227       apps::LaunchPlatformAppWithFileHandler(
    228           profile, extension, task.action_id, file_urls[i].path());
    229     }
    230 
    231     if (!done.is_null())
    232       done.Run(true);
    233     return true;
    234   }
    235   NOTREACHED();
    236   return false;
    237 }
    238 
    239 }  // namespace file_tasks
    240 }  // namespace file_manager
    241