Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Side by Side Diff: chrome/browser/shell_integration_linux.cc

Issue 164280: First step to create application shortcuts on Linux. (Closed)
Patch Set: now tested Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/shell_integration.h" 5 #include "chrome/browser/shell_integration.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 #include <sys/types.h> 10 #include <sys/types.h>
11 #include <unistd.h> 11 #include <unistd.h>
12 12
13 #include <vector> 13 #include <vector>
14 14
15 #include "base/file_path.h"
16 #include "base/file_util.h"
17 #include "base/message_loop.h"
18 #include "base/path_service.h"
15 #include "base/process_util.h" 19 #include "base/process_util.h"
20 #include "base/string_tokenizer.h"
21 #include "base/string_util.h"
22 #include "base/task.h"
23 #include "base/thread.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "googleurl/src/gurl.h"
16 27
17 static const char* GetDesktopName() { 28 namespace {
29
30 const char* GetDesktopName() {
18 #if defined(GOOGLE_CHROME_BUILD) 31 #if defined(GOOGLE_CHROME_BUILD)
19 return "google-chrome.desktop"; 32 return "google-chrome.desktop";
20 #else // CHROMIUM_BUILD 33 #else // CHROMIUM_BUILD
21 static const char* name = NULL; 34 static const char* name = NULL;
22 if (!name) { 35 if (!name) {
23 // Allow $CHROME_DESKTOP to override the built-in value, so that development 36 // Allow $CHROME_DESKTOP to override the built-in value, so that development
24 // versions can set themselves as the default without interfering with 37 // versions can set themselves as the default without interfering with
25 // non-official, packaged versions using the built-in value. 38 // non-official, packaged versions using the built-in value.
26 name = getenv("CHROME_DESKTOP"); 39 name = getenv("CHROME_DESKTOP");
27 if (!name) 40 if (!name)
28 name = "chromium-browser.desktop"; 41 name = "chromium-browser.desktop";
29 } 42 }
30 return name; 43 return name;
31 #endif 44 #endif
32 } 45 }
33 46
47 bool GetDesktopShortcutTemplate(std::string* output) {
48 std::vector<std::string> search_paths;
49
50 const char* xdg_data_home = getenv("XDG_DATA_HOME");
Lei Zhang 2009/08/14 20:18:33 This will not work because almost nobody has $XDG_
51 if (xdg_data_home)
52 search_paths.push_back(xdg_data_home);
53
54 const char* xdg_data_dirs = getenv("XDG_DATA_DIRS");
55 if (xdg_data_dirs) {
56 StringTokenizer tokenizer(xdg_data_dirs, ":");
57 while (tokenizer.GetNext()) {
58 search_paths.push_back(tokenizer.token());
59 }
60 }
61
62 std::string template_filename(GetDesktopName());
63 for (std::vector<std::string>::const_iterator i = search_paths.begin();
64 i != search_paths.end(); ++i) {
65 FilePath path = FilePath(*i).Append(template_filename);
Lei Zhang 2009/08/14 20:18:33 Are you expecting to find /usr/share/google-chrome
Mike Mammarella 2009/08/14 20:56:22 I'm not sure we need to check applnk, but definite
66 if (file_util::PathExists(path))
67 return file_util::ReadFileToString(path, output);
68 }
69
70 return false;
71 }
72
73 class CreateDesktopShortcutTask : public Task {
74 public:
75 CreateDesktopShortcutTask(const GURL& url, const string16& title)
76 : url_(url),
77 title_(title) {
78 }
79
80 virtual void Run() {
81 // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
82 FilePath desktop_path;
83 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
84 return;
85 desktop_path =
86 desktop_path.Append(ShellIntegration::GetDesktopShortcutFilename(url_));
87
88 if (file_util::PathExists(desktop_path))
89 return;
90
91 std::string template_contents;
92 if (!GetDesktopShortcutTemplate(&template_contents))
93 return;
94
95 std::string contents = ShellIntegration::GetDesktopFileContents(
96 template_contents, url_, title_);
97 int bytes_written = file_util::WriteFile(desktop_path, contents.data(),
98 contents.length());
99 if (bytes_written != static_cast<int>(contents.length())) {
100 file_util::Delete(desktop_path, false);
101 }
102 }
103
104 private:
105 const GURL url_; // URL of the web application.
106 const string16 title_; // Title displayed to the user.
107
108 DISALLOW_COPY_AND_ASSIGN(CreateDesktopShortcutTask);
109 };
110
111 } // namespace
112
34 // We delegate the difficult of setting the default browser in Linux desktop 113 // We delegate the difficult of setting the default browser in Linux desktop
35 // environments to a new xdg utility, xdg-settings. We'll have to include a copy 114 // environments to a new xdg utility, xdg-settings. We'll have to include a copy
36 // of it for this to work, obviously, but that's actually the suggested approach 115 // of it for this to work, obviously, but that's actually the suggested approach
37 // for xdg utilities anyway. 116 // for xdg utilities anyway.
38 117
39 bool ShellIntegration::SetAsDefaultBrowser() { 118 bool ShellIntegration::SetAsDefaultBrowser() {
40 std::vector<std::string> argv; 119 std::vector<std::string> argv;
41 argv.push_back("xdg-settings"); 120 argv.push_back("xdg-settings");
42 argv.push_back("set"); 121 argv.push_back("set");
43 argv.push_back("default-web-browser"); 122 argv.push_back("default-web-browser");
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 std::vector<std::string> argv; 170 std::vector<std::string> argv;
92 argv.push_back("xdg-settings"); 171 argv.push_back("xdg-settings");
93 argv.push_back("get"); 172 argv.push_back("get");
94 argv.push_back("default-web-browser"); 173 argv.push_back("default-web-browser");
95 174
96 std::string browser; 175 std::string browser;
97 // We don't care about the return value here. 176 // We don't care about the return value here.
98 base::GetAppOutput(CommandLine(argv), &browser); 177 base::GetAppOutput(CommandLine(argv), &browser);
99 return browser.find("irefox") != std::string::npos; 178 return browser.find("irefox") != std::string::npos;
100 } 179 }
180
181 FilePath ShellIntegration::GetDesktopShortcutFilename(const GURL& url) {
182 std::wstring filename = UTF8ToWide(url.spec()) + L".desktop";
183 file_util::ReplaceIllegalCharacters(&filename, '_');
184
185 // Return BaseName to be absolutely sure we're not vulnerable to a directory
186 // traversal attack.
187 return FilePath::FromWStringHack(filename).BaseName();
188 }
189
190 std::string ShellIntegration::GetDesktopFileContents(
191 const std::string& template_contents, const GURL& url,
192 const string16& title) {
193 // See http://standards.freedesktop.org/desktop-entry-spec/latest/
194 std::string output_buffer;
195 StringTokenizer tokenizer(template_contents, "\n");
196 while (tokenizer.GetNext()) {
197 // TODO(phajdan.jr): Add the icon.
198
199 if (tokenizer.token().substr(0, 5) == "Exec=") {
200 std::string exec_path = tokenizer.token().substr(5);
201 StringTokenizer exec_tokenizer(exec_path, " ");
202 std::string final_path;
203 while (exec_tokenizer.GetNext()) {
204 if (exec_tokenizer.token() != "%U")
205 final_path += exec_tokenizer.token() + " ";
206 }
207 std::string app_switch(StringPrintf("\"--app=%s\"",
Mike Mammarella 2009/08/14 20:56:22 This should use switches::kApp.
208 url.spec().c_str()));
Evan Martin 2009/08/18 14:43:08 Does this make us vulnerable to some sort of comma
209 ReplaceSubstringsAfterOffset(&app_switch, 0, "%", "%%");
210 output_buffer += std::string("Exec=") + final_path + app_switch + "\n";
211 } else if (tokenizer.token().substr(0, 5) == "Name=") {
212 std::string final_title = UTF16ToUTF8(title);
213 // Make sure no endline characters can slip in and possibly introduce
214 // additional lines (like Exec, which makes it a security risk). Also
215 // use the URL as a default when the title is empty.
216 if (final_title.empty() ||
217 final_title.find("\n") != std::string::npos ||
218 final_title.find("\r") != std::string::npos)
219 final_title = url.spec();
220 output_buffer += StringPrintf("Name=%s\n", final_title.c_str());
221 } else if (tokenizer.token().substr(0, 8) == "Comment=") {
222 // Skip the line.
223 } else {
224 output_buffer += tokenizer.token() + "\n";
225 }
226 }
227 return output_buffer;
228 }
229
230 void ShellIntegration::CreateDesktopShortcut(const GURL& url,
231 const string16& title) {
232 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
233 new CreateDesktopShortcutTask(url, title));
234 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698