1// Copyright (c) 2011 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#include "chrome/browser/extensions/file_manager_util.h"
5
6#include "base/json/json_writer.h"
7#include "base/logging.h"
8#include "base/string_util.h"
9#include "base/utf_string_conversions.h"
10#include "base/values.h"
11#include "chrome/browser/metrics/user_metrics.h"
12#include "chrome/browser/platform_util.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/ui/browser.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/browser/ui/webui/mediaplayer_ui.h"
17#include "content/browser/browser_thread.h"
18#include "grit/generated_resources.h"
19#include "third_party/libjingle/source/talk/base/urlencode.h"
20#include "ui/base/l10n/l10n_util.h"
21#include "webkit/fileapi/file_system_context.h"
22#include "webkit/fileapi/file_system_mount_point_provider.h"
23#include "webkit/fileapi/file_system_util.h"
24
25// This is the "well known" url for the file manager extension from
26// browser/resources/file_manager.  In the future we may provide a way to swap
27// out this file manager for an aftermarket part, but not yet.
28const char kBaseFileBrowserUrl[] =
29    "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/main.html";
30// List of file extension we can open in tab.
31const char* kBrowserSupportedExtensions[] = {
32    ".jpg", ".jpeg", ".png", ".webp", ".gif", ".pdf", ".txt", ".html", ".htm"
33};
34// List of file extension that can be handled with the media player.
35const char* kAVExtensions[] = {
36    ".webm", ".mp4", ".m4v", ".mov", ".ogm", ".ogv", ".ogx",
37    ".mp3", ".m4a", ".ogg", ".oga", ".wav",
38/* TODO(zelidrag): Add unsupported ones as we enable them:
39    ".3gp", ".mkv", ".avi", ".divx", ".xvid", ".wmv", ".asf", ".mpeg", ".mpg",
40    ".wma", ".aiff",
41*/
42};
43
44bool IsSupportedBrowserExtension(const char* ext) {
45  for (size_t i = 0; i < arraysize(kBrowserSupportedExtensions); i++) {
46    if (base::strcasecmp(ext, kBrowserSupportedExtensions[i]) == 0) {
47      return true;
48    }
49  }
50  return false;
51}
52
53bool IsSupportedAVExtension(const char* ext) {
54  for (size_t i = 0; i < arraysize(kAVExtensions); i++) {
55    if (base::strcasecmp(ext, kAVExtensions[i]) == 0) {
56      return true;
57    }
58  }
59  return false;
60}
61
62// static
63GURL FileManagerUtil::GetFileBrowserUrl() {
64  return GURL(kBaseFileBrowserUrl);
65}
66
67// static
68bool FileManagerUtil::ConvertFileToFileSystemUrl(
69    Profile* profile, const FilePath& full_file_path, const GURL& origin_url,
70    GURL* url) {
71  fileapi::FileSystemPathManager* path_manager =
72      profile->GetFileSystemContext()->path_manager();
73  fileapi::ExternalFileSystemMountPointProvider* provider =
74      path_manager->external_provider();
75  if (!provider)
76    return false;
77
78  // Find if this file path is managed by the external provider.
79  std::vector<FilePath> root_dirs = provider->GetRootDirectories();
80  for (std::vector<FilePath>::iterator iter = root_dirs.begin();
81       iter != root_dirs.end();
82       ++iter) {
83    FilePath path;
84    std::vector<FilePath::StringType> components;
85    const FilePath& root_path = *iter;
86    root_path.GetComponents(&components);
87    if (!components.size()) {
88      NOTREACHED();
89      continue;
90    }
91    if (root_path.AppendRelativePath(full_file_path, &path)) {
92      GURL base_url = fileapi::GetFileSystemRootURI(origin_url,
93          fileapi::kFileSystemTypeExternal);
94      std::string final_url = base_url.spec();
95      FilePath relative_path(components[components.size() - 1]);
96      *url = GURL(base_url.spec() + relative_path.Append(path).value());
97      return true;
98    }
99  }
100  return false;
101}
102
103// static
104GURL FileManagerUtil::GetFileBrowserUrlWithParams(
105    SelectFileDialog::Type type,
106    const string16& title,
107    const FilePath& default_path,
108    const SelectFileDialog::FileTypeInfo* file_types,
109    int file_type_index,
110    const FilePath::StringType& default_extension) {
111  std::string json = GetArgumentsJson(type, title, default_path, file_types,
112                                      file_type_index, default_extension);
113  return GURL(FileManagerUtil::GetFileBrowserUrl().spec() + "?" +
114              UrlEncodeStringWithoutEncodingSpaceAsPlus(json));
115
116}
117// static
118void FileManagerUtil::ShowFullTabUrl(Profile* profile,
119                                     const FilePath& default_path) {
120  std::string json = GetArgumentsJson(SelectFileDialog::SELECT_NONE, string16(),
121      default_path, NULL, 0, FilePath::StringType());
122  GURL url(std::string(kBaseFileBrowserUrl) + "?" +
123           UrlEncodeStringWithoutEncodingSpaceAsPlus(json));
124  Browser* browser = BrowserList::GetLastActive();
125  if (!browser)
126    return;
127
128  UserMetrics::RecordAction(UserMetricsAction("ShowFileBrowserFullTab"),
129                            profile);
130  browser->ShowSingletonTab(GURL(url));
131}
132
133
134void FileManagerUtil::ViewItem(const FilePath& full_path, bool enqueue) {
135  std::string ext = full_path.Extension();
136  // For things supported natively by the browser, we should open it
137  // in a tab.
138  if (IsSupportedBrowserExtension(ext.data())) {
139    std::string path;
140    path = "file://";
141    path.append(full_path.value());
142    if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
143      bool result = BrowserThread::PostTask(
144          BrowserThread::UI, FROM_HERE,
145          NewRunnableFunction(&ViewItem, full_path, enqueue));
146      DCHECK(result);
147      return;
148    }
149    Browser* browser = BrowserList::GetLastActive();
150    if (browser)
151      browser->AddSelectedTabWithURL(GURL(path), PageTransition::LINK);
152    return;
153  }
154  if (IsSupportedAVExtension(ext.data())) {
155    Browser* browser = BrowserList::GetLastActive();
156    if (!browser)
157      return;
158    MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
159    if (enqueue)
160      mediaplayer->EnqueueMediaFile(browser->profile(), full_path, NULL);
161    else
162      mediaplayer->ForcePlayMediaFile(browser->profile(), full_path, NULL);
163    return;
164  }
165
166  // Unknown file type. Show an error message.
167  BrowserThread::PostTask(
168      BrowserThread::UI, FROM_HERE,
169      NewRunnableFunction(
170          &platform_util::SimpleErrorBox,
171          static_cast<gfx::NativeWindow>(NULL),
172          l10n_util::GetStringUTF16(IDS_FILEBROWSER_ERROR_TITLE),
173          l10n_util::GetStringFUTF16(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE,
174                                     UTF8ToUTF16(full_path.BaseName().value()))
175          ));
176}
177
178// static
179std::string FileManagerUtil::GetArgumentsJson(
180    SelectFileDialog::Type type,
181    const string16& title,
182    const FilePath& default_path,
183    const SelectFileDialog::FileTypeInfo* file_types,
184    int file_type_index,
185    const FilePath::StringType& default_extension) {
186  DictionaryValue arg_value;
187  arg_value.SetString("type", GetDialogTypeAsString(type));
188  arg_value.SetString("title", title);
189  // TODO(zelidrag): Convert local system path into virtual path for File API.
190  arg_value.SetString("defaultPath", default_path.value());
191  arg_value.SetString("defaultExtension", default_extension);
192
193  ListValue* types_list = new ListValue();
194
195  if (file_types) {
196    for (size_t i = 0; i < file_types->extensions.size(); ++i) {
197      ListValue* extensions_list = new ListValue();
198      for (size_t j = 0; j < file_types->extensions[i].size(); ++j) {
199        extensions_list->Set(
200            i, Value::CreateStringValue(file_types->extensions[i][j]));
201      }
202
203      DictionaryValue* dict = new DictionaryValue();
204      dict->Set("extensions", extensions_list);
205
206      if (i < file_types->extension_description_overrides.size()) {
207        string16 desc = file_types->extension_description_overrides[i];
208        dict->SetString("description", desc);
209      }
210
211      dict->SetBoolean("selected",
212                       (static_cast<size_t>(file_type_index) == i));
213
214      types_list->Set(i, dict);
215    }
216  }
217
218  std::string rv;
219  base::JSONWriter::Write(&arg_value, false, &rv);
220
221  return rv;
222}
223
224// static
225std::string FileManagerUtil::GetDialogTypeAsString(
226    SelectFileDialog::Type dialog_type) {
227  std::string type_str;
228  switch (dialog_type) {
229    case SelectFileDialog::SELECT_NONE:
230      type_str = "full-page";
231      break;
232
233    case SelectFileDialog::SELECT_FOLDER:
234      type_str = "folder";
235      break;
236
237    case SelectFileDialog::SELECT_SAVEAS_FILE:
238      type_str = "saveas-file";
239      break;
240
241    case SelectFileDialog::SELECT_OPEN_FILE:
242      type_str = "open-file";
243      break;
244
245    case SelectFileDialog::SELECT_OPEN_MULTI_FILE:
246      type_str = "open-multi-file";
247      break;
248
249    default:
250      NOTREACHED();
251  }
252
253  return type_str;
254}
255