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|. 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. 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. 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. 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 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