1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/file_select_helper.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <string>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_util.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/platform_util.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/child_process_security_policy.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/render_process_host.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_widget_host_view.h"
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/tab_contents/tab_contents.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/view_messages.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/generated_resources.h"
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/base/mime_util.h"
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace {
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// There is only one file-selection happening at any given time,
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// so we allocate an enumeration ID for that purpose.  All IDs from
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// the renderer must start at 0 and increase.
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const int kFileSelectEnumerationId = -1;
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct FileSelectHelper::ActiveDirectoryEnumeration {
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ActiveDirectoryEnumeration() {}
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<DirectoryListerDispatchDelegate> delegate_;
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_refptr<net::DirectoryLister> lister_;
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  RenderViewHost* rvh_;
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<FilePath> results_;
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFileSelectHelper::FileSelectHelper(Profile* profile)
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : profile_(profile),
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      render_view_host_(NULL),
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      select_file_dialog_(),
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dialog_type_(SelectFileDialog::SELECT_OPEN_FILE) {
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFileSelectHelper::~FileSelectHelper() {
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // There may be pending file dialogs, we need to tell them that we've gone
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // away so they don't try and call back to us.
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (select_file_dialog_.get())
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    select_file_dialog_->ListenerDestroyed();
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Stop any pending directory enumeration, prevent a callback, and free
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // allocated memory.
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::map<int, ActiveDirectoryEnumeration*>::iterator iter;
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (iter = directory_enumerations_.begin();
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       iter != directory_enumerations_.end();
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       ++iter) {
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (iter->second->lister_.get()) {
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      iter->second->lister_->set_delegate(NULL);
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      iter->second->lister_->Cancel();
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delete iter->second;
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FileSelectHelper::FileSelected(const FilePath& path,
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                    int index, void* params) {
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!render_view_host_)
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  profile_->set_last_selected_directory(path.DirName());
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (dialog_type_ == SelectFileDialog::SELECT_FOLDER) {
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_);
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::vector<FilePath> files;
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  files.push_back(path);
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_->FilesSelectedInChooser(files);
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We are done with this showing of the dialog.
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_ = NULL;
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FileSelectHelper::MultiFilesSelected(const std::vector<FilePath>& files,
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          void* params) {
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!files.empty())
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    profile_->set_last_selected_directory(files[0].DirName());
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!render_view_host_)
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_->FilesSelectedInChooser(files);
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We are done with this showing of the dialog.
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_ = NULL;
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FileSelectHelper::FileSelectionCanceled(void* params) {
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!render_view_host_)
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If the user cancels choosing a file to upload we pass back an
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // empty vector.
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_->FilesSelectedInChooser(std::vector<FilePath>());
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We are done with this showing of the dialog.
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_ = NULL;
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FileSelectHelper::StartNewEnumeration(const FilePath& path,
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           int request_id,
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           RenderViewHost* render_view_host) {
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration);
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  entry->rvh_ = render_view_host;
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id));
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  entry->lister_ = new net::DirectoryLister(path,
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            true,
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            net::DirectoryLister::NO_SORT,
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            entry->delegate_.get());
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!entry->lister_->Start()) {
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (request_id == kFileSelectEnumerationId)
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FileSelectionCanceled(NULL);
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      render_view_host->DirectoryEnumerationFinished(request_id,
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                     entry->results_);
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    directory_enumerations_[request_id] = entry.release();
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FileSelectHelper::OnListFile(
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int id,
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const net::DirectoryLister::DirectoryListerData& data) {
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ActiveDirectoryEnumeration* entry = directory_enumerations_[id];
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Directory upload returns directories via a "." file, so that
14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // empty directories are included.  This util call just checks
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // the flags in the structure; there's no file I/O going on.
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (file_util::FileEnumerator::IsDirectory(data.info))
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    entry->results_.push_back(data.path.Append(FILE_PATH_LITERAL(".")));
14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  else
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    entry->results_.push_back(data.path);
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FileSelectHelper::OnListDone(int id, int error) {
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This entry needs to be cleaned up when this function is done.
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<ActiveDirectoryEnumeration> entry(directory_enumerations_[id]);
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  directory_enumerations_.erase(id);
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!entry->rvh_)
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (error) {
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    FileSelectionCanceled(NULL);
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (id == kFileSelectEnumerationId)
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    entry->rvh_->FilesSelectedInChooser(entry->results_);
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  else
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    entry->rvh_->DirectoryEnumerationFinished(id, entry->results_);
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSelectFileDialog::FileTypeInfo* FileSelectHelper::GetFileTypesFromAcceptType(
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& accept_types) {
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (accept_types.empty())
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Split the accept-type string on commas.
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::vector<string16> mime_types;
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::SplitStringUsingSubstr(accept_types, ASCIIToUTF16(","), &mime_types);
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (mime_types.empty())
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Create FileTypeInfo and pre-allocate for the first extension list.
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<SelectFileDialog::FileTypeInfo> file_type(
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new SelectFileDialog::FileTypeInfo());
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  file_type->include_all_files = true;
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  file_type->extensions.resize(1);
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::vector<FilePath::StringType>* extensions = &file_type->extensions.back();
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Find the correspondinge extensions.
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int valid_type_count = 0;
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int description_id = 0;
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (size_t i = 0; i < mime_types.size(); ++i) {
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    string16 mime_type = mime_types[i];
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string ascii_mime_type = StringToLowerASCII(UTF16ToASCII(mime_type));
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    TrimWhitespace(ascii_mime_type, TRIM_ALL, &ascii_mime_type);
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (ascii_mime_type.empty())
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      continue;
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    size_t old_extension_size = extensions->size();
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (ascii_mime_type == "image/*") {
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      description_id = IDS_IMAGE_FILES;
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net::GetImageExtensions(extensions);
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (ascii_mime_type == "audio/*") {
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      description_id = IDS_AUDIO_FILES;
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net::GetAudioExtensions(extensions);
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (ascii_mime_type == "video/*") {
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      description_id = IDS_VIDEO_FILES;
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net::GetVideoExtensions(extensions);
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else {
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net::GetExtensionsForMimeType(ascii_mime_type, extensions);
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (extensions->size() > old_extension_size)
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      valid_type_count++;
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
214201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // If no valid extension is added, bail out.
215201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (valid_type_count == 0)
216201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return NULL;
217201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Use a generic description "Custom Files" if either of the following is
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // true:
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // 1) There're multiple types specified, like "audio/*,video/*"
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // 2) There're multiple extensions for a MIME type without parameter, like
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    dialog uses the first extension in the list to form the description,
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    like "EHTML Files". This is not what we want.
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (valid_type_count > 1 ||
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    description_id = IDS_CUSTOM_FILES;
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (description_id) {
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    file_type->extension_description_overrides.push_back(
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        l10n_util::GetStringUTF16(description_id));
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return file_type.release();
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FileSelectHelper::RunFileChooser(
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    RenderViewHost* render_view_host,
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TabContents* tab_contents,
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ViewHostMsg_RunFileChooser_Params& params) {
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(!render_view_host_);
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_ = render_view_host;
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  notification_registrar_.RemoveAll();
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  notification_registrar_.Add(this,
2453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              NotificationType::RENDER_WIDGET_HOST_DESTROYED,
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              Source<RenderViewHost>(render_view_host));
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!select_file_dialog_.get())
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    select_file_dialog_ = SelectFileDialog::Create(this);
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  switch (params.mode) {
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case ViewHostMsg_RunFileChooser_Mode::Open:
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE;
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case ViewHostMsg_RunFileChooser_Mode::OpenMultiple:
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dialog_type_ = SelectFileDialog::SELECT_OPEN_MULTI_FILE;
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case ViewHostMsg_RunFileChooser_Mode::OpenFolder:
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dialog_type_ = SelectFileDialog::SELECT_FOLDER;
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case ViewHostMsg_RunFileChooser_Mode::Save:
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dialog_type_ = SelectFileDialog::SELECT_SAVEAS_FILE;
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    default:
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE;  // Prevent warning.
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NOTREACHED();
2673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<SelectFileDialog::FileTypeInfo> file_types(
2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      GetFileTypesFromAcceptType(params.accept_types));
2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePath default_file_name = params.default_file_name;
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (default_file_name.empty())
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    default_file_name = profile_->last_selected_directory();
2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gfx::NativeWindow owning_window =
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      platform_util::GetTopLevel(render_view_host_->view()->GetNativeView());
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  select_file_dialog_->SelectFile(dialog_type_,
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  params.title,
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  default_file_name,
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  file_types.get(),
281201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                  file_types.get() ? 1 : 0,  // 1-based index.
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  FILE_PATH_LITERAL(""),
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                  tab_contents,
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  owning_window,
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  NULL);
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FileSelectHelper::EnumerateDirectory(int request_id,
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          RenderViewHost* render_view_host,
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          const FilePath& path) {
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_NE(kFileSelectEnumerationId, request_id);
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  StartNewEnumeration(path, request_id, render_view_host);
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FileSelectHelper::Observe(NotificationType type,
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                               const NotificationSource& source,
2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                               const NotificationDetails& details) {
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(type == NotificationType::RENDER_WIDGET_HOST_DESTROYED);
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(Details<RenderViewHost>(details).ptr() == render_view_host_);
3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  render_view_host_ = NULL;
3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenFileSelectObserver::FileSelectObserver(TabContents* tab_contents)
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : TabContentsObserver(tab_contents) {
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenFileSelectObserver::~FileSelectObserver() {
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool FileSelectObserver::OnMessageReceived(const IPC::Message& message) {
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool handled = true;
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IPC_BEGIN_MESSAGE_MAP(FileSelectObserver, message)
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser)
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory)
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IPC_MESSAGE_UNHANDLED(handled = false)
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IPC_END_MESSAGE_MAP()
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return handled;
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FileSelectObserver::OnRunFileChooser(
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ViewHostMsg_RunFileChooser_Params& params) {
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!file_select_helper_.get())
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    file_select_helper_.reset(new FileSelectHelper(tab_contents()->profile()));
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  file_select_helper_->RunFileChooser(tab_contents()->render_view_host(),
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                      tab_contents(),
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                      params);
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FileSelectObserver::OnEnumerateDirectory(int request_id,
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              const FilePath& path) {
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ChildProcessSecurityPolicy* policy =
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ChildProcessSecurityPolicy::GetInstance();
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!policy->CanReadDirectory(
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          tab_contents()->render_view_host()->process()->id(),
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          path)) {
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!file_select_helper_.get())
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    file_select_helper_.reset(new FileSelectHelper(tab_contents()->profile()));
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  file_select_helper_->EnumerateDirectory(request_id,
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          tab_contents()->render_view_host(),
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          path);
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
346