blob: 41ab3c22ee32ab63d13f36d9f608850579bbfe57 [file] [log] [blame]
// Copyright (c) 2010 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/dom_ui/filebrowse_ui.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/weak_ptr.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/base/escape.h"
#include "net/url_request/url_request_file_job.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/mount_library.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#endif
// Maximum number of search results to return in a given search. We should
// eventually remove this.
static const int kMaxSearchResults = 100;
static const char kPropertyPath[] = "path";
static const char kPropertyTitle[] = "title";
static const char kPropertyDirectory[] = "isDirectory";
static const char kPicasawebUserPrefix[] =
"http://picasaweb.google.com/data/feed/api/user/";
static const char kPicasawebDefault[] = "/albumid/default";
static const char kPicasawebDropBox[] = "/home";
static const char kPicasawebBaseUrl[] = "http://picasaweb.google.com/";
static const char kMediaPath[] = "/media";
static const char kFilebrowseURLHash[] = "chrome://filebrowse#";
static const int kPopupLeft = 0;
static const int kPopupTop = 0;
class FileBrowseUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
FileBrowseUIHTMLSource();
// Called when the network layer has requested a resource underneath
// the path we registered.
virtual void StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id);
virtual std::string GetMimeType(const std::string&) const {
return "text/html";
}
private:
~FileBrowseUIHTMLSource() {}
DISALLOW_COPY_AND_ASSIGN(FileBrowseUIHTMLSource);
};
class TaskProxy;
// The handler for Javascript messages related to the "filebrowse" view.
class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
public DOMMessageHandler,
#if defined(OS_CHROMEOS)
public chromeos::MountLibrary::Observer,
#endif
public base::SupportsWeakPtr<FilebrowseHandler>,
public URLFetcher::Delegate,
public DownloadManager::Observer,
public DownloadItem::Observer {
public:
FilebrowseHandler();
virtual ~FilebrowseHandler();
// Init work after Attach.
void Init();
// DirectoryLister::DirectoryListerDelegate methods:
virtual void OnListFile(
const net::DirectoryLister::DirectoryListerData& data);
virtual void OnListDone(int error);
// DOMMessageHandler implementation.
virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
virtual void RegisterMessages();
#if defined(OS_CHROMEOS)
void MountChanged(chromeos::MountLibrary* obj,
chromeos::MountEventType evt,
const std::string& path);
#endif
// DownloadItem::Observer interface
virtual void OnDownloadUpdated(DownloadItem* download);
virtual void OnDownloadFileCompleted(DownloadItem* download) { }
virtual void OnDownloadOpened(DownloadItem* download) { }
// DownloadManager::Observer interface
virtual void ModelChanged();
// Callback for the "getRoots" message.
void HandleGetRoots(const ListValue* args);
void GetChildrenForPath(FilePath& path, bool is_refresh);
void OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
const URLRequestStatus& status,
int response_code,
const ResponseCookies& cookies,
const std::string& data);
// Callback for the "getChildren" message.
void HandleGetChildren(const ListValue* args);
// Callback for the "refreshDirectory" message.
void HandleRefreshDirectory(const ListValue* args);
void HandleIsAdvancedEnabled(const ListValue* args);
// Callback for the "getMetadata" message.
void HandleGetMetadata(const ListValue* args);
// Callback for the "openNewWindow" message.
void OpenNewFullWindow(const ListValue* args);
void OpenNewPopupWindow(const ListValue* args);
// Callback for the "uploadToPicasaweb" message.
void UploadToPicasaweb(const ListValue* args);
// Callback for the "getDownloads" message.
void HandleGetDownloads(const ListValue* args);
void HandleCreateNewFolder(const ListValue* args);
void PlayMediaFile(const ListValue* args);
void EnqueueMediaFile(const ListValue* args);
void HandleDeleteFile(const ListValue* args);
void HandleCopyFile(const ListValue* value);
void CopyFile(const FilePath& src, const FilePath& dest);
void DeleteFile(const FilePath& path);
void FireDeleteComplete(const FilePath& path);
void FireCopyComplete(const FilePath& src, const FilePath& dest);
void HandlePauseToggleDownload(const ListValue* args);
void HandleCancelDownload(const ListValue* args);
void HandleAllowDownload(const ListValue* args);
void ReadInFile();
void FireUploadComplete();
void SendPicasawebRequest();
// Callback for the "validateSavePath" message.
void HandleValidateSavePath(const ListValue* args);
// Validate a save path on file thread.
void ValidateSavePathOnFileThread(const FilePath& save_path);
// Fire save path validation result to JS onValidatedSavePath.
void FireOnValidatedSavePathOnUIThread(bool valid, const FilePath& save_path);
private:
void OpenNewWindow(const ListValue* args, bool popup);
// Clear all download items and their observers.
void ClearDownloadItems();
// Send the current list of downloads to the page.
void SendCurrentDownloads();
void SendNewDownload(DownloadItem* download);
scoped_ptr<ListValue> filelist_value_;
FilePath currentpath_;
Profile* profile_;
TabContents* tab_contents_;
std::string current_file_contents_;
std::string current_file_uploaded_;
int upload_response_code_;
TaskProxy* current_task_;
scoped_refptr<net::DirectoryLister> lister_;
bool is_refresh_;
scoped_ptr<URLFetcher> fetch_;
DownloadManager* download_manager_;
typedef std::vector<DownloadItem*> DownloadList;
DownloadList active_download_items_;
DownloadList download_items_;
bool got_first_download_list_;
DISALLOW_COPY_AND_ASSIGN(FilebrowseHandler);
};
class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
public:
TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
const FilePath& path, const FilePath& dest)
: handler_(handler),
src_(path),
dest_(dest) {}
TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
const FilePath& path)
: handler_(handler),
src_(path) {}
void ReadInFileProxy() {
if (handler_) {
handler_->ReadInFile();
}
}
void DeleteFetcher(URLFetcher* fetch) {
delete fetch;
}
void SendPicasawebRequestProxy() {
if (handler_) {
handler_->SendPicasawebRequest();
}
}
void FireUploadCompleteProxy() {
if (handler_) {
handler_->FireUploadComplete();
}
}
void DeleteFileProxy() {
if (handler_) {
handler_->DeleteFile(src_);
}
}
void CopyFileProxy() {
if (handler_) {
handler_->CopyFile(src_, dest_);
}
}
void FireDeleteCompleteProxy() {
if (handler_) {
handler_->FireDeleteComplete(src_);
}
}
void FireCopyCompleteProxy() {
if (handler_) {
handler_->FireCopyComplete(src_, dest_);
}
}
void ValidateSavePathOnFileThread() {
if (handler_)
handler_->ValidateSavePathOnFileThread(src_);
}
void FireOnValidatedSavePathOnUIThread(bool valid,
const FilePath& save_path) {
if (handler_)
handler_->FireOnValidatedSavePathOnUIThread(valid, save_path);
}
private:
base::WeakPtr<FilebrowseHandler> handler_;
FilePath src_;
FilePath dest_;
friend class base::RefCountedThreadSafe<TaskProxy>;
DISALLOW_COPY_AND_ASSIGN(TaskProxy);
};
////////////////////////////////////////////////////////////////////////////////
//
// FileBrowseHTMLSource
//
////////////////////////////////////////////////////////////////////////////////
FileBrowseUIHTMLSource::FileBrowseUIHTMLSource()
: DataSource(chrome::kChromeUIFileBrowseHost, MessageLoop::current()) {
}
void FileBrowseUIHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
DictionaryValue localized_strings;
// TODO(dhg): Add stirings to localized strings, also add more strings
// that are currently hardcoded.
localized_strings.SetString("title",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_TITLE));
localized_strings.SetString("pause",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_PAUSE));
localized_strings.SetString("resume",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_RESUME));
localized_strings.SetString("scanning",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_SCANNING));
localized_strings.SetString("confirmdelete",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DELETE));
localized_strings.SetString("confirmyes",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_YES));
localized_strings.SetString("confirmcancel",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_CANCEL));
localized_strings.SetString("allowdownload",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DOWNLOAD));
localized_strings.SetString("filenameprompt",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_PROMPT_FILENAME));
localized_strings.SetString("save",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_SAVE));
localized_strings.SetString("newfolder",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_NEW_FOLDER));
localized_strings.SetString("open",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_OPEN));
localized_strings.SetString("picasaweb",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_PICASAWEB));
localized_strings.SetString("flickr",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_FLICKR));
localized_strings.SetString("email",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_EMAIL));
localized_strings.SetString("delete",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_DELETE));
localized_strings.SetString("enqueue",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_ENQUEUE));
localized_strings.SetString("mediapath", kMediaPath);
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
// TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode.
localized_strings.SetString("downloadpath", default_download_path.value());
localized_strings.SetString("error_unknown_file_type",
l10n_util::GetStringUTF16(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE));
SetFontAndTextDirection(&localized_strings);
static const base::StringPiece filebrowse_html(
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_FILEBROWSE_HTML));
const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
filebrowse_html, &localized_strings);
scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
html_bytes->data.resize(full_html.size());
std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
SendResponse(request_id, html_bytes);
}
////////////////////////////////////////////////////////////////////////////////
//
// FilebrowseHandler
//
////////////////////////////////////////////////////////////////////////////////
FilebrowseHandler::FilebrowseHandler()
: profile_(NULL),
tab_contents_(NULL),
is_refresh_(false),
fetch_(NULL),
download_manager_(NULL),
got_first_download_list_(false) {
lister_ = NULL;
#if defined(OS_CHROMEOS)
chromeos::MountLibrary* lib =
chromeos::CrosLibrary::Get()->GetMountLibrary();
lib->AddObserver(this);
#endif
}
FilebrowseHandler::~FilebrowseHandler() {
#if defined(OS_CHROMEOS)
chromeos::MountLibrary* lib =
chromeos::CrosLibrary::Get()->GetMountLibrary();
lib->RemoveObserver(this);
#endif
if (lister_.get()) {
lister_->Cancel();
lister_->set_delegate(NULL);
}
ClearDownloadItems();
download_manager_->RemoveObserver(this);
URLFetcher* fetch = fetch_.release();
if (fetch) {
TaskProxy* task = new TaskProxy(AsWeakPtr(), currentpath_);
task->AddRef();
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
task, &TaskProxy::DeleteFetcher, fetch));
}
}
DOMMessageHandler* FilebrowseHandler::Attach(DOMUI* dom_ui) {
// Create our favicon data source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui->GetProfile()))));
profile_ = dom_ui->GetProfile();
tab_contents_ = dom_ui->tab_contents();
return DOMMessageHandler::Attach(dom_ui);
}
void FilebrowseHandler::Init() {
download_manager_ = profile_->GetDownloadManager();
download_manager_->AddObserver(this);
TaskProxy* task = new TaskProxy(AsWeakPtr(), currentpath_);
task->AddRef();
current_task_ = task;
static bool sent_request = false;
if (!sent_request) {
// If we have not sent a request before, we should do one in order to
// ensure that we have the correct cookies. This is for uploads.
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
task, &TaskProxy::SendPicasawebRequestProxy));
sent_request = true;
}
}
void FilebrowseHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("getRoots",
NewCallback(this, &FilebrowseHandler::HandleGetRoots));
dom_ui_->RegisterMessageCallback("getChildren",
NewCallback(this, &FilebrowseHandler::HandleGetChildren));
dom_ui_->RegisterMessageCallback("getMetadata",
NewCallback(this, &FilebrowseHandler::HandleGetMetadata));
dom_ui_->RegisterMessageCallback("openNewPopupWindow",
NewCallback(this, &FilebrowseHandler::OpenNewPopupWindow));
dom_ui_->RegisterMessageCallback("openNewFullWindow",
NewCallback(this, &FilebrowseHandler::OpenNewFullWindow));
dom_ui_->RegisterMessageCallback("uploadToPicasaweb",
NewCallback(this, &FilebrowseHandler::UploadToPicasaweb));
dom_ui_->RegisterMessageCallback("getDownloads",
NewCallback(this, &FilebrowseHandler::HandleGetDownloads));
dom_ui_->RegisterMessageCallback("createNewFolder",
NewCallback(this, &FilebrowseHandler::HandleCreateNewFolder));
dom_ui_->RegisterMessageCallback("playMediaFile",
NewCallback(this, &FilebrowseHandler::PlayMediaFile));
dom_ui_->RegisterMessageCallback("enqueueMediaFile",
NewCallback(this, &FilebrowseHandler::EnqueueMediaFile));
dom_ui_->RegisterMessageCallback("pauseToggleDownload",
NewCallback(this, &FilebrowseHandler::HandlePauseToggleDownload));
dom_ui_->RegisterMessageCallback("deleteFile",
NewCallback(this, &FilebrowseHandler::HandleDeleteFile));
dom_ui_->RegisterMessageCallback("copyFile",
NewCallback(this, &FilebrowseHandler::HandleCopyFile));
dom_ui_->RegisterMessageCallback("cancelDownload",
NewCallback(this, &FilebrowseHandler::HandleCancelDownload));
dom_ui_->RegisterMessageCallback("allowDownload",
NewCallback(this, &FilebrowseHandler::HandleAllowDownload));
dom_ui_->RegisterMessageCallback("refreshDirectory",
NewCallback(this, &FilebrowseHandler::HandleRefreshDirectory));
dom_ui_->RegisterMessageCallback("isAdvancedEnabled",
NewCallback(this, &FilebrowseHandler::HandleIsAdvancedEnabled));
dom_ui_->RegisterMessageCallback("validateSavePath",
NewCallback(this, &FilebrowseHandler::HandleValidateSavePath));
}
void FilebrowseHandler::FireDeleteComplete(const FilePath& path) {
// We notify the UI by telling it to refresh its contents.
FilePath dir_path = path.DirName();
GetChildrenForPath(dir_path, true);
};
void FilebrowseHandler::FireCopyComplete(const FilePath& src,
const FilePath& dest) {
// Notify the UI somehow.
FilePath dir_path = dest.DirName();
GetChildrenForPath(dir_path, true);
};
void FilebrowseHandler::FireUploadComplete() {
#if defined(OS_CHROMEOS)
DictionaryValue info_value;
info_value.SetString("path", current_file_uploaded_);
std::string username;
chromeos::UserManager* user_man = chromeos::UserManager::Get();
username = user_man->logged_in_user().email();
if (username.empty()) {
LOG(ERROR) << "Unable to get username";
return;
}
int location = username.find_first_of('@',0);
if (location <= 0) {
LOG(ERROR) << "Username not formatted correctly";
return;
}
username = username.erase(username.find_first_of('@',0));
std::string picture_url = kPicasawebBaseUrl;
picture_url += username;
picture_url += kPicasawebDropBox;
info_value.SetString("url", picture_url);
info_value.SetInteger("status_code", upload_response_code_);
dom_ui_->CallJavascriptFunction(L"uploadComplete", info_value);
#endif
}
#if defined(OS_CHROMEOS)
void FilebrowseHandler::MountChanged(chromeos::MountLibrary* obj,
chromeos::MountEventType evt,
const std::string& path) {
if (evt == chromeos::DISK_REMOVED ||
evt == chromeos::DISK_CHANGED) {
dom_ui_->CallJavascriptFunction(L"rootsChanged");
}
}
#endif
void FilebrowseHandler::OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
const URLRequestStatus& status,
int response_code,
const ResponseCookies& cookies,
const std::string& data) {
upload_response_code_ = response_code;
VLOG(1) << "Response code: " << response_code;
VLOG(1) << "Request url: " << url;
if (StartsWithASCII(url.spec(), kPicasawebUserPrefix, true)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(current_task_, &TaskProxy::FireUploadCompleteProxy));
}
fetch_.reset();
}
void FilebrowseHandler::HandleGetRoots(const ListValue* args) {
ListValue results_value;
DictionaryValue info_value;
// TODO(dhg): add other entries, make this more general
#if defined(OS_CHROMEOS)
chromeos::MountLibrary* lib =
chromeos::CrosLibrary::Get()->GetMountLibrary();
const chromeos::MountLibrary::DiskVector& disks = lib->disks();
for (size_t i = 0; i < disks.size(); ++i) {
if (!disks[i].mount_path.empty()) {
DictionaryValue* page_value = new DictionaryValue();
page_value->SetString(kPropertyPath, disks[i].mount_path);
FilePath currentpath(disks[i].mount_path);
std::string filename;
filename = currentpath.BaseName().value();
page_value->SetString(kPropertyTitle, filename);
page_value->SetBoolean(kPropertyDirectory, true);
results_value.Append(page_value);
}
}
#else
DictionaryValue* page_value = new DictionaryValue();
page_value->SetString(kPropertyPath, "/media");
page_value->SetString(kPropertyTitle, "Removeable");
page_value->SetBoolean(kPropertyDirectory, true);
results_value.Append(page_value);
#endif
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
DictionaryValue* download_value = new DictionaryValue();
download_value->SetString(kPropertyPath, default_download_path.value());
download_value->SetString(kPropertyTitle, "File Shelf");
download_value->SetBoolean(kPropertyDirectory, true);
results_value.Append(download_value);
info_value.SetString("functionCall", "getRoots");
info_value.SetString(kPropertyPath, "");
dom_ui_->CallJavascriptFunction(L"browseFileResult",
info_value, results_value);
}
void FilebrowseHandler::HandleCreateNewFolder(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string path = WideToUTF8(ExtractStringValue(args));
FilePath currentpath(path);
if (!file_util::CreateDirectory(currentpath))
LOG(ERROR) << "unable to create directory";
#endif
}
void FilebrowseHandler::PlayMediaFile(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string url = WideToUTF8(ExtractStringValue(args));
GURL gurl(url);
Browser* browser = Browser::GetBrowserForController(
&tab_contents_->controller(), NULL);
MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
mediaplayer->ForcePlayMediaURL(gurl, browser);
#endif
}
void FilebrowseHandler::EnqueueMediaFile(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string url = WideToUTF8(ExtractStringValue(args));
GURL gurl(url);
Browser* browser = Browser::GetBrowserForController(
&tab_contents_->controller(), NULL);
MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
mediaplayer->EnqueueMediaURL(gurl, browser);
#endif
}
void FilebrowseHandler::HandleIsAdvancedEnabled(const ListValue* args) {
#if defined(OS_CHROMEOS)
bool is_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableAdvancedFileSystem);
bool mp_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableMediaPlayer);
DictionaryValue info_value;
info_value.SetBoolean("enabled", is_enabled);
info_value.SetBoolean("mpEnabled", mp_enabled);
dom_ui_->CallJavascriptFunction(L"enabledResult",
info_value);
#endif
}
void FilebrowseHandler::HandleRefreshDirectory(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string path = WideToUTF8(ExtractStringValue(args));
FilePath currentpath(path);
GetChildrenForPath(currentpath, true);
#endif
}
void FilebrowseHandler::HandlePauseToggleDownload(const ListValue* args) {
#if defined(OS_CHROMEOS)
int id;
ExtractIntegerValue(args, &id);
if ((id - 1) >= (int)active_download_items_.size()) {
return;
}
DownloadItem* item = active_download_items_[id];
item->TogglePause();
#endif
}
void FilebrowseHandler::HandleAllowDownload(const ListValue* args) {
#if defined(OS_CHROMEOS)
int id;
ExtractIntegerValue(args, &id);
if ((id - 1) >= (int)active_download_items_.size()) {
return;
}
DownloadItem* item = active_download_items_[id];
download_manager_->DangerousDownloadValidated(item);
#endif
}
void FilebrowseHandler::HandleCancelDownload(const ListValue* args) {
#if defined(OS_CHROMEOS)
int id;
ExtractIntegerValue(args, &id);
if ((id - 1) >= (int)active_download_items_.size()) {
return;
}
DownloadItem* item = active_download_items_[id];
FilePath path = item->full_path();
item->Cancel(true);
FilePath dir_path = path.DirName();
item->Remove(true);
GetChildrenForPath(dir_path, true);
#endif
}
void FilebrowseHandler::OpenNewFullWindow(const ListValue* args) {
OpenNewWindow(args, false);
}
void FilebrowseHandler::OpenNewPopupWindow(const ListValue* args) {
OpenNewWindow(args, true);
}
void FilebrowseHandler::OpenNewWindow(const ListValue* args, bool popup) {
std::string url = WideToUTF8(ExtractStringValue(args));
Browser* browser = popup ?
Browser::CreateForType(Browser::TYPE_APP_PANEL, profile_) :
BrowserList::GetLastActive();
browser::NavigateParams params(browser, GURL(url), PageTransition::LINK);
params.disposition = NEW_FOREGROUND_TAB;
browser::Navigate(&params);
// TODO(beng): The following two calls should be automatic by Navigate().
if (popup) {
// TODO(dhg): Remove these from being hardcoded. Allow javascript
// to specify.
params.browser->window()->SetBounds(gfx::Rect(0, 0, 400, 300));
}
params.browser->window()->Show();
}
void FilebrowseHandler::SendPicasawebRequest() {
#if defined(OS_CHROMEOS)
chromeos::UserManager* user_man = chromeos::UserManager::Get();
std::string username = user_man->logged_in_user().email();
if (username.empty()) {
LOG(ERROR) << "Unable to get username";
return;
}
fetch_.reset(URLFetcher::Create(0,
GURL(kPicasawebBaseUrl),
URLFetcher::GET,
this));
fetch_->set_request_context(profile_->GetRequestContext());
fetch_->Start();
#endif
}
void FilebrowseHandler::ReadInFile() {
#if defined(OS_CHROMEOS)
// Get the users username
std::string username;
chromeos::UserManager* user_man = chromeos::UserManager::Get();
username = user_man->logged_in_user().email();
if (username.empty()) {
LOG(ERROR) << "Unable to get username";
return;
}
int location = username.find_first_of('@',0);
if (location <= 0) {
LOG(ERROR) << "Username not formatted correctly";
return;
}
username = username.erase(username.find_first_of('@',0));
std::string url = kPicasawebUserPrefix;
url += username;
url += kPicasawebDefault;
FilePath currentpath(current_file_uploaded_);
// Get the filename
std::string filename;
filename = currentpath.BaseName().value();
std::string filecontents;
if (!file_util::ReadFileToString(currentpath, &filecontents)) {
LOG(ERROR) << "Unable to read this file:" << currentpath.value();
return;
}
fetch_.reset(URLFetcher::Create(0,
GURL(url),
URLFetcher::POST,
this));
fetch_->set_upload_data("image/jpeg", filecontents);
// Set the filename on the server
std::string slug = "Slug: ";
slug += filename;
fetch_->set_extra_request_headers(slug);
fetch_->set_request_context(profile_->GetRequestContext());
fetch_->Start();
#endif
}
// This is just a prototype for allowing generic uploads to various sites
// TODO(dhg): Remove this and implement general upload.
void FilebrowseHandler::UploadToPicasaweb(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string search_string = WideToUTF8(ExtractStringValue(args));
current_file_uploaded_ = search_string;
// ReadInFile();
FilePath current_path(search_string);
TaskProxy* task = new TaskProxy(AsWeakPtr(), current_path);
task->AddRef();
current_task_ = task;
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
task, &TaskProxy::ReadInFileProxy));
#endif
}
void FilebrowseHandler::GetChildrenForPath(FilePath& path, bool is_refresh) {
filelist_value_.reset(new ListValue());
currentpath_ = path;
if (lister_.get()) {
lister_->Cancel();
lister_->set_delegate(NULL);
lister_ = NULL;
}
is_refresh_ = is_refresh;
#if defined(OS_CHROMEOS)
// Don't allow listing files in inaccessible dirs.
if (net::URLRequestFileJob::AccessDisabled(path))
return;
#endif // OS_CHROMEOS
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
if (currentpath_ == default_download_path) {
lister_ = new net::DirectoryLister(currentpath_,
false,
net::DirectoryLister::DATE,
this);
} else {
lister_ = new net::DirectoryLister(currentpath_, this);
}
lister_->Start();
}
void FilebrowseHandler::HandleGetChildren(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string path = WideToUTF8(ExtractStringValue(args));
FilePath currentpath(path);
filelist_value_.reset(new ListValue());
GetChildrenForPath(currentpath, false);
#endif
}
void FilebrowseHandler::OnListFile(
const net::DirectoryLister::DirectoryListerData& data) {
#if defined(OS_WIN)
if (data.info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
return;
}
#elif defined(OS_POSIX)
if (data.info.filename[0] == '.') {
return;
}
#endif
DictionaryValue* file_value = new DictionaryValue();
#if defined(OS_WIN)
int64 size = (static_cast<int64>(data.info.nFileSizeHigh) << 32) |
data.info.nFileSizeLow;
file_value->SetString(kPropertyTitle, data.info.cFileName);
file_value->SetString(kPropertyPath,
currentpath_.Append(data.info.cFileName).value());
file_value->SetBoolean(kPropertyDirectory,
(data.info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false);
#elif defined(OS_POSIX)
file_value->SetString(kPropertyTitle, data.info.filename);
file_value->SetString(kPropertyPath,
currentpath_.Append(data.info.filename).value());
file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
#endif
filelist_value_->Append(file_value);
}
void FilebrowseHandler::OnListDone(int error) {
DictionaryValue info_value;
if (is_refresh_) {
info_value.SetString("functionCall", "refresh");
} else {
info_value.SetString("functionCall", "getChildren");
}
info_value.SetString(kPropertyPath, currentpath_.value());
dom_ui_->CallJavascriptFunction(L"browseFileResult",
info_value, *(filelist_value_.get()));
SendCurrentDownloads();
}
void FilebrowseHandler::HandleGetMetadata(const ListValue* args) {
}
void FilebrowseHandler::HandleGetDownloads(const ListValue* args) {
ModelChanged();
}
void FilebrowseHandler::ModelChanged() {
ClearDownloadItems();
std::vector<DownloadItem*> downloads;
download_manager_->GetAllDownloads(FilePath(), &downloads);
std::vector<DownloadItem*> new_downloads;
// Scan for any in progress downloads and add ourself to them as an observer.
for (DownloadList::iterator it = downloads.begin();
it != downloads.end(); ++it) {
DownloadItem* download = *it;
// We want to know what happens as the download progresses and be notified
// when the user validates the dangerous download.
if (download->state() == DownloadItem::IN_PROGRESS ||
download->safety_state() == DownloadItem::DANGEROUS) {
download->AddObserver(this);
active_download_items_.push_back(download);
}
DownloadList::iterator item = find(download_items_.begin(),
download_items_.end(),
download);
if (item == download_items_.end() && got_first_download_list_) {
SendNewDownload(download);
}
new_downloads.push_back(download);
}
download_items_.swap(new_downloads);
got_first_download_list_ = true;
SendCurrentDownloads();
}
void FilebrowseHandler::SendNewDownload(DownloadItem* download) {
ListValue results_value;
results_value.Append(download_util::CreateDownloadItemValue(download, -1));
dom_ui_->CallJavascriptFunction(L"newDownload", results_value);
}
void FilebrowseHandler::DeleteFile(const FilePath& path) {
if (!file_util::Delete(path, true)) {
LOG(ERROR) << "unable to delete directory";
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(current_task_, &TaskProxy::FireDeleteCompleteProxy));
}
void FilebrowseHandler::CopyFile(const FilePath& src, const FilePath& dest) {
if (file_util::DirectoryExists(src)) {
if (!file_util::CopyDirectory(src, dest, true)) {
LOG(ERROR) << "unable to copy directory:" << src.value();
}
} else {
if (!file_util::CopyFile(src, dest)) {
LOG(ERROR) << "unable to copy file" << src.value();
}
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(current_task_, &TaskProxy::FireCopyCompleteProxy));
}
void FilebrowseHandler::HandleDeleteFile(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string path = WideToUTF8(ExtractStringValue(args));
FilePath currentpath(path);
// Don't allow file deletion in inaccessible dirs.
if (net::URLRequestFileJob::AccessDisabled(currentpath))
return;
for (unsigned int x = 0; x < active_download_items_.size(); x++) {
FilePath item = active_download_items_[x]->full_path();
if (item == currentpath) {
active_download_items_[x]->Cancel(true);
active_download_items_[x]->Remove(true);
FilePath dir_path = item.DirName();
GetChildrenForPath(dir_path, true);
return;
}
}
TaskProxy* task = new TaskProxy(AsWeakPtr(), currentpath);
task->AddRef();
current_task_ = task;
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
task, &TaskProxy::DeleteFileProxy));
#endif
}
void FilebrowseHandler::HandleCopyFile(const ListValue* value) {
#if defined(OS_CHROMEOS)
if (value && value->GetType() == Value::TYPE_LIST) {
const ListValue* list_value = static_cast<const ListValue*>(value);
std::string src;
std::string dest;
// Get path string.
if (list_value->GetString(0, &src) &&
list_value->GetString(1, &dest)) {
FilePath SrcPath = FilePath(src);
FilePath DestPath = FilePath(dest);
// Don't allow file copy to inaccessible dirs.
if (net::URLRequestFileJob::AccessDisabled(DestPath))
return;
TaskProxy* task = new TaskProxy(AsWeakPtr(), SrcPath, DestPath);
task->AddRef();
current_task_ = task;
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
task, &TaskProxy::CopyFileProxy));
} else {
LOG(ERROR) << "Unable to get string";
return;
}
}
#endif
}
void FilebrowseHandler::HandleValidateSavePath(const ListValue* args) {
std::string string_path;
if (!args || !args->GetString(0, &string_path)) {
FireOnValidatedSavePathOnUIThread(false, FilePath()); // Invalid save path.
return;
}
FilePath save_path(string_path);
#if defined(OS_CHROMEOS)
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), save_path);
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(task.get(), &TaskProxy::ValidateSavePathOnFileThread));
#else
// No save path checking for non-ChromeOS platforms.
FireOnValidatedSavePathOnUIThread(true, save_path);
#endif
}
void FilebrowseHandler::ValidateSavePathOnFileThread(
const FilePath& save_path) {
#if defined(OS_CHROMEOS)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
// Get containing folder of save_path.
FilePath save_dir = save_path.DirName();
// Valid save path must be inside default download dir.
bool valid = default_download_path == save_dir ||
file_util::ContainsPath(default_download_path, save_dir);
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), save_path);
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(task.get(),
&TaskProxy::FireOnValidatedSavePathOnUIThread,
valid, save_path));
#endif
}
void FilebrowseHandler::FireOnValidatedSavePathOnUIThread(bool valid,
const FilePath& save_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
FundamentalValue valid_value(valid);
StringValue path_value(save_path.value());
dom_ui_->CallJavascriptFunction(L"onValidatedSavePath",
valid_value, path_value);
}
void FilebrowseHandler::OnDownloadUpdated(DownloadItem* download) {
DownloadList::iterator it = find(active_download_items_.begin(),
active_download_items_.end(),
download);
if (it == active_download_items_.end())
return;
const int id = static_cast<int>(it - active_download_items_.begin());
scoped_ptr<DictionaryValue> download_item(
download_util::CreateDownloadItemValue(download, id));
dom_ui_->CallJavascriptFunction(L"downloadUpdated", *download_item.get());
}
void FilebrowseHandler::ClearDownloadItems() {
for (DownloadList::iterator it = active_download_items_.begin();
it != active_download_items_.end(); ++it) {
(*it)->RemoveObserver(this);
}
active_download_items_.clear();
}
void FilebrowseHandler::SendCurrentDownloads() {
ListValue results_value;
for (DownloadList::iterator it = active_download_items_.begin();
it != active_download_items_.end(); ++it) {
int index = static_cast<int>(it - active_download_items_.begin());
results_value.Append(download_util::CreateDownloadItemValue(*it, index));
}
dom_ui_->CallJavascriptFunction(L"downloadsList", results_value);
}
////////////////////////////////////////////////////////////////////////////////
//
// FileBrowseUI
//
////////////////////////////////////////////////////////////////////////////////
FileBrowseUI::FileBrowseUI(TabContents* contents) : HtmlDialogUI(contents) {
FilebrowseHandler* handler = new FilebrowseHandler();
AddMessageHandler((handler)->Attach(this));
handler->Init();
FileBrowseUIHTMLSource* html_source = new FileBrowseUIHTMLSource();
// Set up the chrome://filebrowse/ source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
// static
Browser* FileBrowseUI::OpenPopup(Profile* profile,
const std::string& hashArgument,
int width,
int height) {
// Get existing pop up for given hashArgument.
Browser* browser = GetPopupForPath(hashArgument, profile);
// Create new browser if no matching pop up found.
if (browser == NULL) {
browser = Browser::CreateForType(Browser::TYPE_APP_PANEL, profile);
std::string url;
if (hashArgument.empty()) {
url = chrome::kChromeUIFileBrowseURL;
} else {
url = kFilebrowseURLHash;
url.append(hashArgument);
}
browser::NavigateParams params(browser, GURL(url), PageTransition::LINK);
params.disposition = NEW_FOREGROUND_TAB;
browser::Navigate(&params);
// TODO(beng): The following two calls should be automatic by Navigate().
params.browser->window()->SetBounds(gfx::Rect(kPopupLeft,
kPopupTop,
width,
height));
params.browser->window()->Show();
} else {
browser->window()->Show();
}
return browser;
}
Browser* FileBrowseUI::GetPopupForPath(const std::string& path,
Profile* profile) {
std::string current_path = path;
if (current_path.empty()) {
bool is_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableAdvancedFileSystem);
if (!is_enabled) {
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
current_path = default_download_path.value();
}
}
for (BrowserList::const_iterator it = BrowserList::begin();
it != BrowserList::end(); ++it) {
if (((*it)->type() == Browser::TYPE_APP_PANEL)) {
TabContents* tab_contents = (*it)->GetSelectedTabContents();
DCHECK(tab_contents);
if (!tab_contents)
continue;
const GURL& url = tab_contents->GetURL();
if (url.SchemeIs(chrome::kChromeUIScheme) &&
url.host() == chrome::kChromeUIFileBrowseHost &&
url.ref() == current_path &&
(*it)->profile() == profile) {
return (*it);
}
}
}
return NULL;
}
const int FileBrowseUI::kPopupWidth = 250;
const int FileBrowseUI::kPopupHeight = 300;
const int FileBrowseUI::kSmallPopupWidth = 250;
const int FileBrowseUI::kSmallPopupHeight = 50;