File Source: URLHandler.java
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 package com.dmdirc.util;
24
25 import com.dmdirc.Main;
26 import com.dmdirc.config.ConfigManager;
27 import com.dmdirc.config.IdentityManager;
28 import com.dmdirc.logger.ErrorLevel;
29 import com.dmdirc.logger.Logger;
30
31 import java.awt.Desktop;
32 import java.io.IOException;
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.net.URL;
36 import java.util.ArrayList;
37 import java.util.Date;
38 import java.util.List;
39
40 /** Handles URLs. */
41 public class URLHandler {
42
43 /** Config manager. */
44 private final ConfigManager config;
45 /** Singleton instance. */
/*
P/P * Method: com.dmdirc.util.URLHandler__static_init
*
* Postconditions:
* me == &new URLHandler(URLHandler__static_init#1)
* new URLHandler(URLHandler__static_init#1) num objects == 1
* init'ed(me.config)
* init'ed(me.desktop)
*/
46 private static final URLHandler me = new URLHandler();
47 /** Desktop handler. */
48 private final Desktop desktop;
49 /** The time a browser was last launched. */
50 private static Date lastLaunch;
51
52 /** Instantiates a new URL Handler. */
/*
P/P * Method: void com.dmdirc.util.URLHandler()
*
* Postconditions:
* init'ed(this.config)
* init'ed(this.desktop)
*
* Test Vectors:
* java.awt.Desktop:isDesktopSupported(...)@55: {0}, {1}
*/
53 private URLHandler() {
54 config = IdentityManager.getGlobalConfig();
55 if (Desktop.isDesktopSupported()) {
56 desktop = Desktop.getDesktop();
57 } else {
58 desktop = null;
59 }
60 }
61
62 /**
63 * Gets an instance of URLHandler.
64 *
65 * @return URLHandler instance
66 */
67 public static URLHandler getURLHander() {
/*
P/P * Method: URLHandler getURLHander()
*
* Postconditions:
* return_value == &new URLHandler(URLHandler__static_init#1)
*/
68 synchronized (me) {
69 return me;
70 }
71 }
72
73 /**
74 * Launches an application for a given url.
75 *
76 * @param urlString URL to parse
77 */
78 public void launchApp(final String urlString) {
79 URI uri;
80 try {
/*
P/P * Method: void launchApp(String)
*
* Preconditions:
* (soft) init'ed(lastLaunch)
* (soft) this.config != null
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
*
* Postconditions:
* lastLaunch == One-of{old lastLaunch, &new Date(launchApp#1*)}
* init'ed(lastLaunch)
* new Date(launchApp#1*) num objects <= 1
*
* Test Vectors:
* java.net.URI:getScheme(...)@82: Inverse{null}, Addr_Set{null}
*/
81 uri = new URI(urlString);
82 if (uri.getScheme() == null) {
83 uri = new URI("http://" + urlString);
84 }
85 } catch (URISyntaxException ex) {
86 Logger.userError(ErrorLevel.LOW, "Invalid URL: " + ex.getMessage());
87 return;
88 }
89
90 launchApp(uri);
91 }
92
93 /**
94 * Launches an application for a given url.
95 *
96 * @param url URL to parse
97 */
98 public void launchApp(final URL url) {
99 URI uri;
100 try {
/*
P/P * Method: void launchApp(URL)
*
* Preconditions:
* (soft) init'ed(lastLaunch)
* (soft) this.config != null
* (soft) url != null
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
* java.net.URL:toURI(...)@101 != null
*
* Postconditions:
* lastLaunch == One-of{old lastLaunch, &new Date(launchApp#1*)}
* init'ed(lastLaunch)
* new Date(launchApp#1*) num objects <= 1
*
* Test Vectors:
* java.net.URI:getScheme(...)@102: Inverse{null}, Addr_Set{null}
*/
101 uri = url.toURI();
102 if (uri.getScheme() == null) {
103 uri = new URI("http://" + url.toString());
104 }
105 } catch (URISyntaxException ex) {
106 Logger.userError(ErrorLevel.LOW, "Invalid URL: " + ex.getMessage());
107 return;
108 }
109
110 launchApp(uri);
111 }
112
113 /**
114 * Launches an application for a given url.
115 *
116 * @param uri URL to parse
117 */
118 public void launchApp(final URI uri) {
/*
P/P * Method: void launchApp(URI)
*
* Preconditions:
* init'ed(lastLaunch)
* (soft) this.config != null
* (soft) uri != null
*
* Presumptions:
* com.dmdirc.Main:getUI(...)@133 != null
* com.dmdirc.Main:getUI(...)@141 != null
* com.dmdirc.Main:getUI(...)@149 != null
* com.dmdirc.Main:getUI(...)@154 != null
* com.dmdirc.config.ConfigManager:getOption(...)@137 != null
* ...
*
* Postconditions:
* lastLaunch == &new Date(launchApp#1)
* new Date(launchApp#1) num objects == 1
*
* Test Vectors:
* lastLaunch: Addr_Set{null}, Inverse{null}
* com.dmdirc.config.ConfigManager:getOptionBool(...)@122: {0}, {1}
* com.dmdirc.config.ConfigManager:hasOptionString(...)@132: {1}, {0}
* java.lang.String:equals(...)@139: {0}, {1}
* java.lang.String:equals(...)@148: {0}, {1}
* java.lang.String:equals(...)@151: {0}, {1}
*/
119 final Date oldLaunch = lastLaunch;
120 lastLaunch = new Date();
121
122 if (IdentityManager.getGlobalConfig().getOptionBool("browser",
123 "uselaunchdelay") && oldLaunch != null) {
124 final Long diff = lastLaunch.getTime() - oldLaunch.getTime();
125
126 if (diff < IdentityManager.getGlobalConfig().getOptionInt("browser",
127 "launchdelay")) {
128 return;
129 }
130 }
131
132 if (!config.hasOptionString("protocol", uri.getScheme())) {
133 Main.getUI().showURLDialog(uri);
134 return;
135 }
136
137 final String command = config.getOption("protocol", uri.getScheme());
138
139 if ("DMDIRC".equals(command)) {
140 try {
141 Main.getUI().getStatusBar().setMessage("Connecting to: " +
142 uri.toString());
143 new IrcAddress(uri.toString()).connect();
144 } catch (InvalidAddressException ex) {
145 Logger.userError(ErrorLevel.LOW, "Invalid IRC Address: " +
146 ex.getMessage());
147 }
148 } else if ("BROWSER".equals(command)) {
149 Main.getUI().getStatusBar().setMessage("Opening: " + uri.toString());
150 execBrowser(uri);
151 } else if ("MAIL".equals(command)) {
152 execMail(uri);
153 } else {
154 Main.getUI().getStatusBar().setMessage("Opening: " + uri.toString());
155 execApp(substituteParams(uri, command));
156 }
157 }
158
159 /**
160 * Substitutes variables into a command
161 *
162 * @param url data url
163 * @param command command to be substituted
164 *
165 * @return Substituted command
166 */
167 public String substituteParams(final URI url, final String command) {
/*
P/P * Method: String substituteParams(URI, String)
*
* Preconditions:
* command != null
* url != null
*
* Presumptions:
* java.lang.String:indexOf(...)@207 <= 232-2
*
* Postconditions:
* return_value != null
*
* Test Vectors:
* java.lang.String:indexOf(...)@204: {-231..-2, 0..232-1}, {-1}
* java.lang.String:isEmpty(...)@203: {1}, {0}
* java.net.URI:getFragment(...)@179: Addr_Set{null}, Inverse{null}
* java.net.URI:getHost(...)@183: Addr_Set{null}, Inverse{null}
* java.net.URI:getPath(...)@187: Addr_Set{null}, Inverse{null}
* java.net.URI:getPort(...)@199: {-231..0}, {1..232-1}
* java.net.URI:getQuery(...)@195: Addr_Set{null}, Inverse{null}
* java.net.URI:getScheme(...)@191: Addr_Set{null}, Inverse{null}
* java.net.URI:getUserInfo(...)@168: Addr_Set{null}, Inverse{null}
*/
168 final String userInfo = url.getUserInfo();
169 String fragment = "";
170 String host = "";
171 String path = "";
172 String protocol = "";
173 String query = "";
174 String username = "";
175 String password = "";
176 String port = "";
177 String newCommand = command;
178
179 if (url.getFragment() != null) {
180 fragment = url.getFragment();
181 }
182
183 if (url.getHost() != null) {
184 host = url.getHost();
185 }
186
187 if (url.getPath() != null) {
188 path = url.getPath();
189 }
190
191 if (url.getScheme() != null) {
192 protocol = url.getScheme();
193 }
194
195 if (url.getQuery() != null) {
196 query = url.getQuery();
197 }
198
199 if (url.getPort() > 0) {
200 port = String.valueOf(url.getPort());
201 }
202
203 if (userInfo != null && !userInfo.isEmpty()) {
204 if (userInfo.indexOf(':') == -1) {
205 username = userInfo;
206 } else {
207 final int pos = userInfo.indexOf(':');
208 username = userInfo.substring(0, pos);
209 password = userInfo.substring(pos + 1);
210 }
211 }
212
213 newCommand = newCommand.replaceAll("\\$url", url.toString());
214 newCommand = newCommand.replaceAll("\\$fragment", fragment);
215 newCommand = newCommand.replaceAll("\\$host", host);
216 newCommand = newCommand.replaceAll("\\$path", path);
217 newCommand = newCommand.replaceAll("\\$port", port);
218 newCommand = newCommand.replaceAll("\\$query", query);
219 newCommand = newCommand.replaceAll("\\$protocol", protocol);
220 newCommand = newCommand.replaceAll("\\$username", username);
221 newCommand = newCommand.replaceAll("\\$password", password);
222
223 return newCommand;
224 }
225
226 /**
227 * Launches an application.
228 *
229 * @param command Application and arguments
230 */
231 private void execApp(final String command) {
232 try {
/*
P/P * Method: void execApp(String)
*
* Preconditions:
* (soft) command != null
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
* java.lang.Runtime:getRuntime(...)@233 != null
*/
233 Runtime.getRuntime().exec(parseArguments(command));
234 } catch (IOException ex) {
235 Logger.userError(ErrorLevel.LOW, "Unable to run application: ",
236 ex.getMessage());
237 }
238 }
239
240 /**
241 * Parses the specified command into an array of arguments. Arguments are
242 * separated by spaces. Multi-word arguments may be specified by starting
243 * the argument with a quote (") and finishing it with a quote (").
244 *
245 * @param command The command to parse
246 * @return An array of arguments corresponding to the command
247 */
248 protected static String[] parseArguments(final String command) {
/*
P/P * Method: String[] parseArguments(String)
*
* Preconditions:
* command != null
*
* Presumptions:
* java.util.List:size(...)@278 >= 0
*
* Postconditions:
* init'ed(return_value)
*/
249 final List<String> args = new ArrayList<String>();
250 final StringBuilder builder = new StringBuilder();
251 boolean inquote = false;
252
253 for (String word : command.split(" ")) {
254 if (word.endsWith("\"") && inquote) {
255 args.add(builder.toString() + ' ' + word.substring(0, word.length() - 1));
256 builder.delete(0, builder.length());
257 inquote = false;
258 } else if (inquote) {
259 if (builder.length() > 0) {
260 builder.append(' ');
261 }
262
263 builder.append(word);
264 } else if (word.startsWith("\"") && !word.endsWith("\"")) {
265 inquote = true;
266 builder.append(word.substring(1));
267 } else if (word.startsWith("\"") && word.endsWith("\"")) {
268 if (word.length() == 1) {
269 inquote = true;
270 } else {
271 args.add(word.substring(1, word.length() - 1));
272 }
273 } else {
274 args.add(word);
275 }
276 }
277
278 return args.toArray(new String[args.size()]);
279 }
280
281 /**
282 * Opens the specified URL in the users browser.
283 *
284 * @param url URL to open
285 */
286 private void execBrowser(final URI url) {
/*
P/P * Method: void execBrowser(URI)
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
* init'ed(java.awt.Desktop$Action.BROWSE)
*
* Test Vectors:
* this.desktop: Addr_Set{null}, Inverse{null}
* java.awt.Desktop:isSupported(...)@287: {0}, {1}
*/
287 if (desktop != null &&
288 desktop.isSupported(Desktop.Action.BROWSE)) {
289 try {
290 desktop.browse(url);
291 } catch (IOException ex) {
292 Logger.userError(ErrorLevel.LOW,
293 "Unable to open URL: " + ex.getMessage());
294 }
295 } else {
296 Logger.userError(ErrorLevel.LOW,
297 "Unable to open your browser: Your desktop enviroment is " +
298 "not supported, please go to the URL Handlers section of " +
299 "the preferences dialog and set the path to your browser " +
300 "manually");
301 }
302 }
303
304 /**
305 * Opens the specified URL in the users mail client.
306 *
307 * @param url URL to open
308 */
309 private void execMail(final URI url) {
/*
P/P * Method: void execMail(URI)
*
* Presumptions:
* init'ed(com.dmdirc.logger.ErrorLevel.LOW)
* init'ed(java.awt.Desktop$Action.MAIL)
*
* Test Vectors:
* this.desktop: Addr_Set{null}, Inverse{null}
* java.awt.Desktop:isSupported(...)@310: {0}, {1}
*/
310 if (desktop != null && desktop.isSupported(Desktop.Action.MAIL)) {
311 try {
312 desktop.mail(url);
313 } catch (IOException ex) {
314 Logger.userError(ErrorLevel.LOW,
315 "Unable to open URL: " + ex.getMessage());
316 }
317 } else {
318 Logger.userError(ErrorLevel.LOW,
319 "Unable to open your mail client: Your desktop enviroment is " +
320 "not supported, please go to the URL Handlers section of " +
321 "the preferences dialog and set the path to your browser " +
322 "manually");
323 }
324 }
325 }
SofCheck Inspector Build Version : 2.17854
| URLHandler.java |
2009-Jun-25 01:54:24 |
| URLHandler.class |
2009-Sep-02 17:04:17 |