1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_applications/web_app.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <shlobj.h>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_WIN)
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/command_line.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/i18n/file_util_icu.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/md5.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/string_util.h"
173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/windows_version.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_util.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/environment.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_LINUX)
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/icon_util.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_WIN)
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst FilePath::CharType kIconChecksumFileExt[] = FILE_PATH_LITERAL(".ico.md5");
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if |ch| is in visible ASCII range and not one of
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "/ \ : * ? " < > | ; ,".
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsValidFilePathChar(char16 c) {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (c < 32)
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (c) {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '/':
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '\\':
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case ':':
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '*':
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '?':
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '"':
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '<':
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '>':
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case '|':
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case ';':
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case ',':
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_WIN)
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns relative directory of given web app url.
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenFilePath GetWebAppDir(const ShellIntegration::ShortcutInfo& info) {
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!info.extension_id.empty()) {
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::string app_name =
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        web_app::GenerateApplicationNameFromExtensionId(info.extension_id);
7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN)
7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return FilePath(UTF8ToWide(app_name));
7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#elif defined(OS_POSIX)
7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return FilePath(app_name);
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FilePath::StringType host;
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FilePath::StringType scheme_port;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    host = UTF8ToWide(info.url.host());
8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    scheme_port = (info.url.has_scheme() ? UTF8ToWide(info.url.scheme())
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        : L"http") + FILE_PATH_LITERAL("_") +
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        (info.url.has_port() ? UTF8ToWide(info.url.port()) : L"80");
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX)
8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    host = info.url.host();
8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    scheme_port = info.url.scheme() + FILE_PATH_LITERAL("_") + info.url.port();
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return FilePath(host).Append(scheme_port);
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(TOOLKIT_VIEWS)
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Predicator for sorting images from largest to smallest.
954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool IconPrecedes(const WebApplicationInfo::IconInfo& left,
964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                  const WebApplicationInfo::IconInfo& right) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return left.width < right.width;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_WIN)
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Calculates image checksum using MD5.
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetImageCheckSum(const SkBitmap& image, MD5Digest* digest) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(digest);
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkAutoLockPixels image_lock(image);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Sum(image.getPixels(), image.getSize(), digest);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Saves |image| as an |icon_file| with the checksum.
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SaveIconWithCheckSum(const FilePath& icon_file, const SkBitmap& image) {
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!IconUtil::CreateIconFileFromSkBitmap(image, icon_file))
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Digest digest;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetImageCheckSum(image, &digest);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath cheksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt));
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return file_util::WriteFile(cheksum_file,
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              reinterpret_cast<const char*>(&digest),
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              sizeof(digest)) == sizeof(digest);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if |icon_file| is missing or different from |image|.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ShouldUpdateIcon(const FilePath& icon_file, const SkBitmap& image) {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath checksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt));
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns true if icon_file or checksum file is missing.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!file_util::PathExists(icon_file) ||
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !file_util::PathExists(checksum_file))
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Digest persisted_image_checksum;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (sizeof(persisted_image_checksum) != file_util::ReadFile(checksum_file,
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      reinterpret_cast<char*>(&persisted_image_checksum),
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      sizeof(persisted_image_checksum)))
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Digest downloaded_image_checksum;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetImageCheckSum(image, &downloaded_image_checksum);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update icon if checksums are not equal.
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return memcmp(&persisted_image_checksum, &downloaded_image_checksum,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                sizeof(MD5Digest)) != 0;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_WIN)
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Represents a task that creates web application shortcut. This runs on
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file thread and schedules the callback (if any) on the calling thread
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// when finished (either success or failure).
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CreateShortcutTask : public Task {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CreateShortcutTask(const FilePath& profile_path,
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     const ShellIntegration::ShortcutInfo& shortcut_info,
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     web_app::CreateShortcutCallback* callback);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  class CreateShortcutCallbackTask : public Task {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   public:
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CreateShortcutCallbackTask(web_app::CreateShortcutCallback* callback,
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        bool success)
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        : callback_(callback),
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          success_(success) {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Overridden from Task:
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    virtual void Run() {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      callback_->Run(success_);
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   private:
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_app::CreateShortcutCallback* callback_;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool success_;
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Overridden from Task:
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Run();
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns true if shortcut is created successfully.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool CreateShortcut();
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Path to store persisted data for web app.
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath web_app_path_;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Out copy of profile path.
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath profile_path_;
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Our copy of short cut data.
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ShellIntegration::ShortcutInfo shortcut_info_;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Callback when task is finished.
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_app::CreateShortcutCallback* callback_;
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop* message_loop_;
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(CreateShortcutTask);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCreateShortcutTask::CreateShortcutTask(
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const FilePath& profile_path,
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ShellIntegration::ShortcutInfo& shortcut_info,
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_app::CreateShortcutCallback* callback)
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : web_app_path_(web_app::internals::GetWebAppDataDirectory(
20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        web_app::GetDataDir(profile_path),
20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        shortcut_info)),
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_path_(profile_path),
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_info_(shortcut_info),
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      callback_(callback),
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      message_loop_(MessageLoop::current()) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(message_loop_ != NULL);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CreateShortcutTask::Run() {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = CreateShortcut();
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (callback_ != NULL)
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    message_loop_->PostTask(FROM_HERE,
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new CreateShortcutCallbackTask(callback_, success));
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateShortcutTask::CreateShortcut() {
222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<base::Environment> env(base::Environment::Create());
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string shortcut_template;
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!ShellIntegration::GetDesktopShortcutTemplate(env.get(),
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                    &shortcut_template)) {
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ShellIntegration::CreateDesktopShortcut(shortcut_info_, shortcut_template);
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;  // assuming always success.
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN)
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Shortcut paths under which to create shortcuts.
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<FilePath> shortcut_paths;
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Locations to add to shortcut_paths.
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  struct {
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const bool& use_this_location;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int location_id;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const wchar_t* sub_dir;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } locations[] = {
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    {
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_info_.create_on_desktop,
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::DIR_USER_DESKTOP,
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }, {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_info_.create_in_applications_menu,
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::DIR_START_MENU,
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }, {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_info_.create_in_quick_launch_bar,
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For Win7, create_in_quick_launch_bar means pinning to taskbar. Use
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // base::PATH_START as a flag for this case.
256731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      (base::win::GetVersion() >= base::win::VERSION_WIN7) ?
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          base::PATH_START : base::DIR_APP_DATA,
258731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      (base::win::GetVersion() >= base::win::VERSION_WIN7) ?
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NULL : L"Microsoft\\Internet Explorer\\Quick Launch"
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Populate shortcut_paths.
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < arraysize(locations); ++i) {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (locations[i].use_this_location) {
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FilePath path;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Skip the Win7 case.
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (locations[i].location_id == base::PATH_START)
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!PathService::Get(locations[i].location_id, &path)) {
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (locations[i].sub_dir != NULL)
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        path = path.Append(locations[i].sub_dir);
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_paths.push_back(path);
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool pin_to_taskbar =
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_info_.create_in_quick_launch_bar &&
286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      (base::win::GetVersion() >= base::win::VERSION_WIN7);
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For Win7's pinning support, any shortcut could be used. So we only create
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the shortcut file when there is no shortcut file will be created. That is,
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // user only selects "Pin to taskbar".
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (pin_to_taskbar && shortcut_paths.empty()) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Creates the shortcut in web_app_path_ in this case.
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shortcut_paths.push_back(web_app_path_);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (shortcut_paths.empty()) {
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ensure web_app_path_ exists.
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!file_util::PathExists(web_app_path_) &&
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !file_util::CreateDirectory(web_app_path_)) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Generates file name to use with persisted ico and shortcut file.
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FilePath file_name =
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      web_app::internals::GetSanitizedFileName(shortcut_info_.title);
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates an ico file to use with shortcut.
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath icon_file = web_app_path_.Append(file_name).ReplaceExtension(
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FILE_PATH_LITERAL(".ico"));
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!web_app::internals::CheckAndSaveIcon(icon_file,
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            shortcut_info_.favicon)) {
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath chrome_exe;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Working directory.
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath chrome_folder = chrome_exe.DirName();
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CommandLine cmd_line =
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     ShellIntegration::CommandLineArgsForLauncher(shortcut_info_.url,
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                  shortcut_info_.extension_id);
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(evan): we rely on the fact that command_line_string() is
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // properly quoted for a Windows command line.  The method on
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // CommandLine should probably be renamed to better reflect that
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // fact.
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::wstring wide_switches(cmd_line.command_line_string());
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sanitize description
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (shortcut_info_.description.length() >= MAX_PATH)
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shortcut_info_.description.resize(MAX_PATH - 1);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Generates app id from web app url and profile path.
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string app_name =
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      web_app::GenerateApplicationNameFromInfo(shortcut_info_);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring app_id = ShellIntegration::GetAppId(
34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      UTF8ToWide(app_name), profile_path_);
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath shortcut_to_pin;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = true;
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < shortcut_paths.size(); ++i) {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath shortcut_file = shortcut_paths[i].Append(file_name).
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ReplaceExtension(FILE_PATH_LITERAL(".lnk"));
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int unique_number = download_util::GetUniquePathNumber(shortcut_file);
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (unique_number == -1) {
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success = false;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (unique_number > 0) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      download_util::AppendNumberToPath(&shortcut_file, unique_number);
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    success &= file_util::CreateShortcutLink(chrome_exe.value().c_str(),
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        shortcut_file.value().c_str(),
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chrome_folder.value().c_str(),
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        wide_switches.c_str(),
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        shortcut_info_.description.c_str(),
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        icon_file.value().c_str(),
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0,
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        app_id.c_str());
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Any shortcut would work for the pinning. We use the first one.
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (success && pin_to_taskbar && shortcut_to_pin.empty())
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shortcut_to_pin = shortcut_file;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success && pin_to_taskbar) {
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!shortcut_to_pin.empty()) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success &= file_util::TaskbarPinShortcutLink(
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          shortcut_to_pin.value().c_str());
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success = false;
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return success;
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NOTIMPLEMENTED();
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace web_app {
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// The following string is used to build the directory name for
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// shortcuts to chrome applications (the kind which are installed
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// from a CRX).  Application shortcuts to URLs use the {host}_{path}
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// for the name of this directory.  Hosts can't include an underscore.
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// By starting this string with an underscore, we ensure that there
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// are no naming conflicts.
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const char* kCrxAppPrefix = "_crx_";
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace internals {
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Returns sanitized name that could be used as a file name
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenFilePath GetSanitizedFileName(const string16& name) {
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  string16 file_name;
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < name.length(); ++i) {
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    char16 c = name[i];
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!IsValidFilePathChar(c))
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      c = '_';
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    file_name += c;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return FilePath(file_name);
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Saves |image| to |icon_file| if the file is outdated and refresh shell's
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// icon cache to ensure correct icon is displayed. Returns true if icon_file
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// is up to date or successfully updated.
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool CheckAndSaveIcon(const FilePath& icon_file, const SkBitmap& image) {
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (ShouldUpdateIcon(icon_file, image)) {
430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (SaveIconWithCheckSum(icon_file, image)) {
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Refresh shell's icon cache. This call is quite disruptive as user would
432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // see explorer rebuilding the icon cache. It would be great that we find
433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // a better way to achieve this.
434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT,
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     NULL, NULL);
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif  // OS_WIN
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Returns data directory for given web app url
446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenFilePath GetWebAppDataDirectory(const FilePath& root_dir,
447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                const ShellIntegration::ShortcutInfo& info) {
448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return root_dir.Append(GetWebAppDir(info));
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace internals
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::string GenerateApplicationNameFromInfo(
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ShellIntegration::ShortcutInfo& shortcut_info) {
455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!shortcut_info.extension_id.empty()) {
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return web_app::GenerateApplicationNameFromExtensionId(
457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        shortcut_info.extension_id);
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return web_app::GenerateApplicationNameFromURL(
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        shortcut_info.url);
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstd::string GenerateApplicationNameFromURL(const GURL& url) {
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string t;
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  t.append(url.host());
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  t.append("_");
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  t.append(url.path());
4693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return t;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::string GenerateApplicationNameFromExtensionId(const std::string& id) {
47372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string t(web_app::kCrxAppPrefix);
47472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  t.append(id);
47572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return t;
47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
47772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CreateShortcut(
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const FilePath& data_dir,
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ShellIntegration::ShortcutInfo& shortcut_info,
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CreateShortcutCallback* callback) {
482731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new CreateShortcutTask(data_dir, shortcut_info, callback));
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsValidUrl(const GURL& url) {
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const char* const kValidUrlSchemes[] = {
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kFileScheme,
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kFtpScheme,
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kHttpScheme,
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kHttpsScheme,
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kExtensionScheme,
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (url.SchemeIs(kValidUrlSchemes[i]))
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetDataDir(const FilePath& profile_path) {
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return profile_path.Append(chrome::kWebAppDirname);
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_VIEWS)
5084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid GetIconsInfo(const WebApplicationInfo& app_info,
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  IconInfoList* icons) {
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(icons);
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  icons->clear();
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < app_info.icons.size(); ++i) {
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We only take square shaped icons (i.e. width == height).
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (app_info.icons[i].width == app_info.icons[i].height) {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      icons->push_back(app_info.icons[i]);
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::sort(icons->begin(), icons->end(), &IconPrecedes);
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(TOOLKIT_USES_GTK)
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::string GetWMClassFromAppName(std::string app_name) {
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  file_util::ReplaceIllegalCharactersInPath(&app_name, '_');
527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TrimString(app_name, "_", &app_name);
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return app_name;
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace web_app
533