1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #if !defined(OS_CHROMEOS)
6
7 #include "chrome/browser/ui/webui/options/advanced_options_utils.h"
8
9 #include "base/environment.h"
10 #include "base/file_util.h"
11 #include "base/nix/xdg_util.h"
12 #include "base/process_util.h"
13 #include "base/string_tokenizer.h"
14 #include "chrome/browser/ui/browser_list.h"
15 #include "content/browser/browser_thread.h"
16 #include "content/browser/tab_contents/tab_contents.h"
17 #include "content/common/process_watcher.h"
18 #include "ui/base/gtk/gtk_signal.h"
19
20 // Command used to configure GNOME proxy settings. The command was renamed
21 // in January 2009, so both are used to work on both old and new systems.
22 const char* kOldGNOMEProxyConfigCommand[] = {"gnome-network-preferences", NULL};
23 const char* kGNOMEProxyConfigCommand[] = {"gnome-network-properties", NULL};
24 // KDE3 and KDE4 are only slightly different, but incompatible. Go figure.
25 const char* kKDE3ProxyConfigCommand[] = {"kcmshell", "proxy", NULL};
26 const char* kKDE4ProxyConfigCommand[] = {"kcmshell4", "proxy", NULL};
27
28 // The URL for Linux proxy configuration help when not running under a
29 // supported desktop environment.
30 const char kLinuxProxyConfigUrl[] = "about:linux-proxy-config";
31
32 struct ProxyConfigCommand {
33 std::string binary;
34 const char** argv;
35 };
36
37 namespace {
38
39 // Search $PATH to find one of the commands. Store the full path to
40 // it in the |binary| field and the command array index in in |index|.
SearchPATH(ProxyConfigCommand * commands,size_t ncommands,size_t * index)41 bool SearchPATH(ProxyConfigCommand* commands, size_t ncommands, size_t* index) {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
43 const char* path = getenv("PATH");
44 if (!path)
45 return false;
46 FilePath bin_path;
47 CStringTokenizer tk(path, path + strlen(path), ":");
48 // Search $PATH looking for the commands in order.
49 while (tk.GetNext()) {
50 for (size_t i = 0; i < ncommands; i++) {
51 bin_path = FilePath(tk.token()).Append(commands[i].argv[0]);
52 if (file_util::PathExists(bin_path)) {
53 commands[i].binary = bin_path.value();
54 if (index)
55 *index = i;
56 return true;
57 }
58 }
59 }
60 // Did not find any of the binaries in $PATH.
61 return false;
62 }
63
64 // Show the proxy config URL in the given tab.
ShowLinuxProxyConfigUrl(TabContents * tab_contents)65 void ShowLinuxProxyConfigUrl(TabContents* tab_contents) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
67 scoped_ptr<base::Environment> env(base::Environment::Create());
68 const char* name = base::nix::GetDesktopEnvironmentName(env.get());
69 if (name)
70 LOG(ERROR) << "Could not find " << name << " network settings in $PATH";
71 tab_contents->OpenURL(GURL(kLinuxProxyConfigUrl), GURL(),
72 NEW_FOREGROUND_TAB, PageTransition::LINK);
73 }
74
75 // Start the given proxy configuration utility.
StartProxyConfigUtil(TabContents * tab_contents,const ProxyConfigCommand & command)76 void StartProxyConfigUtil(TabContents* tab_contents,
77 const ProxyConfigCommand& command) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
79 std::vector<std::string> argv;
80 argv.push_back(command.binary);
81 for (size_t i = 1; command.argv[i]; i++)
82 argv.push_back(command.argv[i]);
83 base::file_handle_mapping_vector no_files;
84 base::ProcessHandle handle;
85 if (!base::LaunchApp(argv, no_files, false, &handle)) {
86 LOG(ERROR) << "StartProxyConfigUtil failed to start " << command.binary;
87 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
88 NewRunnableFunction(&ShowLinuxProxyConfigUrl, tab_contents));
89 return;
90 }
91 ProcessWatcher::EnsureProcessGetsReaped(handle);
92 }
93
94 // Detect, and if possible, start the appropriate proxy config utility. On
95 // failure to do so, show the Linux proxy config URL in a new tab instead.
DetectAndStartProxyConfigUtil(TabContents * tab_contents)96 void DetectAndStartProxyConfigUtil(TabContents* tab_contents) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
98 scoped_ptr<base::Environment> env(base::Environment::Create());
99
100 ProxyConfigCommand command;
101 bool found_command = false;
102 switch (base::nix::GetDesktopEnvironment(env.get())) {
103 case base::nix::DESKTOP_ENVIRONMENT_GNOME: {
104 size_t index;
105 ProxyConfigCommand commands[2];
106 commands[0].argv = kGNOMEProxyConfigCommand;
107 commands[1].argv = kOldGNOMEProxyConfigCommand;
108 found_command = SearchPATH(commands, 2, &index);
109 if (found_command)
110 command = commands[index];
111 break;
112 }
113
114 case base::nix::DESKTOP_ENVIRONMENT_KDE3:
115 command.argv = kKDE3ProxyConfigCommand;
116 found_command = SearchPATH(&command, 1, NULL);
117 break;
118
119 case base::nix::DESKTOP_ENVIRONMENT_KDE4:
120 command.argv = kKDE4ProxyConfigCommand;
121 found_command = SearchPATH(&command, 1, NULL);
122 break;
123
124 case base::nix::DESKTOP_ENVIRONMENT_XFCE:
125 case base::nix::DESKTOP_ENVIRONMENT_OTHER:
126 break;
127 }
128
129 if (found_command) {
130 StartProxyConfigUtil(tab_contents, command);
131 } else {
132 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
133 NewRunnableFunction(&ShowLinuxProxyConfigUrl, tab_contents));
134 }
135 }
136
137 } // anonymous namespace
138
ShowNetworkProxySettings(TabContents * tab_contents)139 void AdvancedOptionsUtilities::ShowNetworkProxySettings(
140 TabContents* tab_contents) {
141 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
142 NewRunnableFunction(&DetectAndStartProxyConfigUtil, tab_contents));
143 }
144
145 #endif // !defined(OS_CHROMEOS)
146