You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

URLHandler.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * Copyright (c) 2006-2017 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  5. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  7. * permit persons to whom the Software is furnished to do so, subject to the following conditions:
  8. *
  9. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
  10. * Software.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  14. * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  15. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. */
  17. package com.dmdirc.ui.core.util;
  18. import com.dmdirc.events.StatusBarMessageEvent;
  19. import com.dmdirc.events.UnknownURLEvent;
  20. import com.dmdirc.interfaces.ConnectionManager;
  21. import com.dmdirc.events.eventbus.EventBus;
  22. import com.dmdirc.interfaces.config.AggregateConfigProvider;
  23. import com.dmdirc.ui.StatusMessage;
  24. import com.dmdirc.util.CommandUtils;
  25. import java.awt.Desktop;
  26. import java.io.IOException;
  27. import java.net.URI;
  28. import java.net.URISyntaxException;
  29. import java.net.URL;
  30. import java.util.Date;
  31. import javax.inject.Inject;
  32. import org.slf4j.Logger;
  33. import org.slf4j.LoggerFactory;
  34. import static com.dmdirc.util.LogUtils.USER_ERROR;
  35. /** Handles URLs. */
  36. public class URLHandler {
  37. private static final Logger LOG = LoggerFactory.getLogger(URLHandler.class);
  38. /** The time a browser was last launched. */
  39. private static Date lastLaunch;
  40. /** Event bus to fire unknown protocol errors on. */
  41. private final EventBus eventBus;
  42. /** Config manager. */
  43. private final AggregateConfigProvider config;
  44. /** Server manager to use to connect to servers. */
  45. private final ConnectionManager connectionManager;
  46. /** Desktop handler. */
  47. private final Desktop desktop;
  48. /**
  49. * Instantiates a new URL Handler.
  50. *
  51. * @param eventBus Event bus to fire unknown protocol errors on.
  52. * @param globalConfig Config to retrieve settings from
  53. * @param connectionManager Server manager to connect to servers
  54. */
  55. @Inject
  56. public URLHandler(
  57. final EventBus eventBus,
  58. final AggregateConfigProvider globalConfig,
  59. final ConnectionManager connectionManager) {
  60. this.eventBus = eventBus;
  61. this.config = globalConfig;
  62. this.connectionManager = connectionManager;
  63. this.desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
  64. }
  65. /**
  66. * Launches an application for a given url.
  67. *
  68. * @param urlString URL to parse
  69. */
  70. public void launchApp(final String urlString) {
  71. final String sanitisedString = getSanitisedString(urlString);
  72. URI uri;
  73. try {
  74. uri = new URI(sanitisedString);
  75. if (uri.getScheme() == null) {
  76. uri = new URI("http://" + sanitisedString);
  77. }
  78. } catch (URISyntaxException ex) {
  79. LOG.info(USER_ERROR, "Unavlid URL: {}", ex.getMessage(), ex);
  80. return;
  81. }
  82. launchApp(uri);
  83. }
  84. /**
  85. * Sanitises the specified string so that it may be used as a {@link URI}. Sanitisation consists
  86. * of:
  87. * <ul>
  88. * <li>replacing any pipe character with its hex escape</li>
  89. * <li>replacing any hash character in the fragment with its hex escape</li>
  90. * </ul>
  91. *
  92. * @since 0.6.5
  93. * @param urlString The string to be sanitised
  94. *
  95. * @return A sanitised version of the specified string.
  96. */
  97. protected static String getSanitisedString(final String urlString) {
  98. String sanitisedString = urlString.replace("|", "%7C");
  99. final int index = sanitisedString.indexOf('#');
  100. if (sanitisedString.lastIndexOf('#') > index) {
  101. sanitisedString = sanitisedString.substring(0, index + 1)
  102. + sanitisedString.substring(index + 1).replace("#", "%23");
  103. }
  104. return sanitisedString;
  105. }
  106. /**
  107. * Launches an application for a given url.
  108. *
  109. * @param url URL to parse
  110. */
  111. public void launchApp(final URL url) {
  112. URI uri;
  113. try {
  114. uri = url.toURI();
  115. if (uri.getScheme() == null) {
  116. uri = new URI("http://" + url);
  117. }
  118. } catch (URISyntaxException ex) {
  119. LOG.info(USER_ERROR, "Invalid URL: {}", ex.getMessage(), ex);
  120. return;
  121. }
  122. launchApp(uri);
  123. }
  124. /**
  125. * Launches an application for a given url.
  126. *
  127. * @param uri URL to parse
  128. */
  129. public void launchApp(final URI uri) {
  130. final Date oldLaunch = lastLaunch;
  131. lastLaunch = new Date();
  132. if (config.getOptionBool("browser", "uselaunchdelay") && oldLaunch != null) {
  133. final Long diff = lastLaunch.getTime() - oldLaunch.getTime();
  134. if (diff < config.getOptionInt("browser", "launchdelay")) {
  135. return;
  136. }
  137. }
  138. if (!config.hasOptionString("protocol", uri.getScheme().toLowerCase())) {
  139. eventBus.publish(new UnknownURLEvent(uri));
  140. return;
  141. }
  142. final String command = config.getOption("protocol", uri.getScheme().toLowerCase());
  143. switch (command) {
  144. case "DMDIRC":
  145. eventBus.publishAsync(new StatusBarMessageEvent(
  146. new StatusMessage("Connecting to: " + uri, config)));
  147. connectionManager.connectToAddress(uri);
  148. break;
  149. case "BROWSER":
  150. eventBus.publishAsync(new StatusBarMessageEvent(
  151. new StatusMessage("Opening: " + uri, config)));
  152. execBrowser(uri);
  153. break;
  154. case "MAIL":
  155. execMail(uri);
  156. break;
  157. default:
  158. eventBus.publishAsync(new StatusBarMessageEvent(
  159. new StatusMessage("Opening: " + uri, config)));
  160. execApp(substituteParams(uri, command));
  161. break;
  162. }
  163. }
  164. /**
  165. * Substitutes variables into a command.
  166. *
  167. * @param url data url
  168. * @param command command to be substituted
  169. *
  170. * @return Substituted command
  171. */
  172. public static String substituteParams(final URI url, final String command) {
  173. final String userInfo = url.getUserInfo();
  174. String fragment = "";
  175. String host = "";
  176. String path = "";
  177. String protocol = "";
  178. String query = "";
  179. String username = "";
  180. String password = "";
  181. String port = "";
  182. String newCommand = command;
  183. if (url.getFragment() != null) {
  184. fragment = url.getFragment();
  185. }
  186. if (url.getHost() != null) {
  187. host = url.getHost();
  188. }
  189. if (url.getPath() != null) {
  190. path = url.getPath();
  191. }
  192. if (url.getScheme() != null) {
  193. protocol = url.getScheme();
  194. }
  195. if (url.getQuery() != null) {
  196. query = url.getQuery();
  197. }
  198. if (url.getPort() > 0) {
  199. port = String.valueOf(url.getPort());
  200. }
  201. if (userInfo != null && !userInfo.isEmpty()) {
  202. if (userInfo.indexOf(':') == -1) {
  203. username = userInfo;
  204. } else {
  205. final int pos = userInfo.indexOf(':');
  206. username = userInfo.substring(0, pos);
  207. password = userInfo.substring(pos + 1);
  208. }
  209. }
  210. newCommand = newCommand.replace("$url", url.toString());
  211. newCommand = newCommand.replace("$fragment", fragment);
  212. newCommand = newCommand.replace("$host", host);
  213. newCommand = newCommand.replace("$path", path);
  214. newCommand = newCommand.replace("$port", port);
  215. newCommand = newCommand.replace("$query", query);
  216. newCommand = newCommand.replace("$protocol", protocol);
  217. newCommand = newCommand.replace("$username", username);
  218. newCommand = newCommand.replace("$password", password);
  219. return newCommand;
  220. }
  221. /**
  222. * Launches an application.
  223. *
  224. * @param command Application and arguments
  225. */
  226. private void execApp(final String command) {
  227. try {
  228. Runtime.getRuntime().exec(CommandUtils.parseArguments(command));
  229. } catch (IOException ex) {
  230. LOG.info(USER_ERROR, "Unable to run application: {}", ex.getMessage(), ex);
  231. }
  232. }
  233. /**
  234. * Opens the specified URL in the users browser.
  235. *
  236. * @param url URL to open
  237. */
  238. private void execBrowser(final URI url) {
  239. if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
  240. try {
  241. desktop.browse(url);
  242. } catch (IOException ex) {
  243. LOG.info(USER_ERROR, "Unable to open URL: {}", ex.getMessage(), ex);
  244. }
  245. } else {
  246. LOG.info(USER_ERROR, "Unable to open your browser: Your desktop enviroment is " +
  247. "not supported, please go to the URL Handlers section of " +
  248. "the preferences dialog and set the path to your browser manually");
  249. }
  250. }
  251. /**
  252. * Opens the specified URL in the users mail client.
  253. *
  254. * @param url URL to open
  255. */
  256. private void execMail(final URI url) {
  257. if (desktop != null && desktop.isSupported(Desktop.Action.MAIL)) {
  258. try {
  259. desktop.mail(url);
  260. } catch (IOException ex) {
  261. LOG.info(USER_ERROR, "Unable to open URL: {}", ex.getMessage(), ex);
  262. }
  263. } else {
  264. LOG.info(USER_ERROR, "Unable to open your mail client: Your desktop enviroment is " +
  265. "not supported, please go to the URL Handlers section of " +
  266. "the preferences dialog and set the path to your browser manually");
  267. }
  268. }
  269. }