Changeset 9738db7
- Timestamp:
- Dec 12, 2018 8:12:07 PM (2 years ago)
- Branches:
- master
- Children:
- 6c3c227c
- Parents:
- 51bf23a
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
apps/systray/java/src/net/i2p/apps/systray/UrlLauncher.java
r51bf23a r9738db7 21 21 import java.net.URI; 22 22 import java.net.URISyntaxException; 23 import java.util.Arrays; 24 import java.util.ArrayList; 25 import java.util.List; 23 26 import java.util.Locale; 24 27 … … 27 30 import static net.i2p.app.ClientAppState.*; 28 31 import net.i2p.util.I2PAppThread; 32 import net.i2p.util.Log; 29 33 import net.i2p.util.ShellCommand; 30 34 import net.i2p.util.SystemVersion; … … 47 51 private final ClientAppManager _mgr; 48 52 private final String[] _args; 53 private final Log _log; 49 54 50 55 private static final int WAIT_TIME = 5*1000; … … 70 75 "opera -newpage", 71 76 "firefox", 77 "chromium-browser", 72 78 "mozilla", 73 79 "netscape", … … 83 89 * ClientApp constructor used from clients.config 84 90 * 91 * @param mgr null OK 92 * @param args URL in args[0] or null args for router console 85 93 * @since 0.9.18 86 94 */ … … 88 96 _state = UNINITIALIZED; 89 97 _context = context; 98 _log = _context.logManager().getLog(UrlLauncher.class); 90 99 _mgr = mgr; 91 100 if (args == null || args.length <= 0) … … 104 113 _state = UNINITIALIZED; 105 114 _context = I2PAppContext.getGlobalContext(); 115 _log = _context.logManager().getLog(UrlLauncher.class); 106 116 _mgr = null; 107 117 _args = null; … … 168 178 * browsers. 169 179 * 170 * BLOCKING 180 * BLOCKING. This repeatedly probes the server port at the given url 181 * until it is apparently ready. 171 182 * 172 183 * @param url The URL to open. … … 177 188 */ 178 189 public boolean openUrl(String url) throws IOException { 190 if (_log.shouldDebug()) _log.debug("Waiting for server"); 179 191 waitForServer(url); 192 if (_log.shouldDebug()) _log.debug("Done waiting for server"); 180 193 if (validateUrlFormat(url)) { 181 194 String cbrowser = _context.getProperty(PROP_BROWSER); … … 186 199 String osName = System.getProperty("os.name"); 187 200 if (osName.toLowerCase(Locale.US).startsWith("mac os x")) { 188 189 if (_shellCommand.executeSilentAndWaitTimed("open " + url, 5)) 201 String[] args = new String[] { "open", url }; 202 if (_log.shouldDebug()) _log.debug("Execute: " + Arrays.toString(args)); 203 if (_shellCommand.executeSilentAndWaitTimed(args , 5)) 190 204 return true; 191 192 205 } else { 193 206 return false; 194 207 } 195 196 if (_shellCommand.executeSilentAndWaitTimed("iexplore " + url, 5)) 208 String[] args = new String[] { "iexplore", url }; 209 if (_log.shouldDebug()) _log.debug("Execute: " + Arrays.toString(args)); 210 if (_shellCommand.executeSilentAndWaitTimed(args , 5)) 197 211 return true; 198 212 } else if (SystemVersion.isWindows()) { 199 String browserString = "\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" -nohome"; 200 BufferedReader bufferedReader = null; 201 202 File foo = new File(_context.getTempDir(), "browser.reg"); 203 _shellCommand.executeSilentAndWait("regedit /E \"" + foo.getAbsolutePath() + "\" \"HKEY_CLASSES_ROOT\\http\\shell\\open\\command\""); 204 205 try { 206 bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(foo), "UTF-16")); 207 for (String line; (line = bufferedReader.readLine()) != null; ) { 208 if (line.startsWith("@=")) { 209 // we should really use the whole line and replace %1 with the url 210 browserString = line.substring(3, line.toLowerCase(Locale.US).indexOf(".exe") + 4); 211 if (browserString.startsWith("\\\"")) 212 browserString = browserString.substring(2); 213 browserString = "\"" + browserString + "\""; 213 String[] browserString = new String[] { "C:\\Program Files\\Internet Explorer\\iexplore.exe", "-nohome", url }; 214 File foo = new File(_context.getTempDir(), "browser" + _context.random().nextLong() + ".reg"); 215 String[] args = new String[] { "regedit", "/E", foo.getAbsolutePath(), "HKEY_CLASSES_ROOT\\http\\shell\\open\\command" }; 216 if (_log.shouldDebug()) _log.debug("Execute: " + Arrays.toString(args)); 217 boolean ok = _shellCommand.executeSilentAndWait(args); 218 if (ok) { 219 BufferedReader bufferedReader = null; 220 try { 221 bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(foo), "UTF-16")); 222 for (String line; (line = bufferedReader.readLine()) != null; ) { 223 // @="\"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe\" -osint -url \"%1\"" 224 if (line.startsWith("@=")) { 225 if (_log.shouldDebug()) _log.debug("From RegEdit: " + line); 226 line = line.substring(2).trim(); 227 if (line.startsWith("\"") && line.endsWith("\"")) 228 line = line.substring(1, line.length() - 1); 229 line = line.replace("\\\\", "\\"); 230 line = line.replace("\\\"", "\""); 231 if (_log.shouldDebug()) _log.debug("Mod RegEdit: " + line); 232 // "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -osint -url "%1" 233 // use the whole line 234 String[] aarg = parseArgs(line, url); 235 if (aarg.length > 0) { 236 browserString = aarg; 237 break; 238 } 239 } 214 240 } 241 } catch (IOException e) { 242 if (_log.shouldWarn()) 243 _log.warn("Reading regedit output", e); 244 } finally { 245 if (bufferedReader != null) 246 try { bufferedReader.close(); } catch (IOException ioe) {} 247 foo.delete(); 215 248 } 216 try { 217 bufferedReader.close(); 218 } catch (IOException e) { 219 // No worries. 220 } 221 foo.delete(); 222 } catch (IOException e) { 223 // Defaults to IE. 224 } finally { 225 if (bufferedReader != null) 226 try { bufferedReader.close(); } catch (IOException ioe) {} 249 } else if (_log.shouldWarn()) { 250 _log.warn("Regedit Failed: " + Arrays.toString(args)); 227 251 } 228 if (_shellCommand.executeSilentAndWaitTimed(browserString + ' ' + url, 5)) 252 if (_log.shouldDebug()) _log.debug("Execute: " + Arrays.toString(browserString)); 253 if (_shellCommand.executeSilentAndWaitTimed(browserString, 5)) 229 254 return true; 255 if (_log.shouldInfo()) _log.info("Failed: " + Arrays.toString(browserString)); 230 256 } else { 231 257 // fall through 232 258 } 259 String[] args = new String[2]; 260 args[1] = url; 233 261 for (int i = 0; i < BROWSERS.length; i++) { 234 if (_shellCommand.executeSilentAndWaitTimed(BROWSERS[i] + ' ' + url, 5)) 262 args[0] = BROWSERS[i]; 263 if (_log.shouldDebug()) _log.debug("Execute: " + Arrays.toString(args)); 264 if (_shellCommand.executeSilentAndWaitTimed(args, 5)) 235 265 return true; 266 if (_log.shouldInfo()) _log.info("Failed: " + Arrays.toString(args)); 236 267 } 237 268 } … … 241 272 /** 242 273 * Opens the given URL with the given browser. 243 * 244 * BLOCKING 274 * As of 0.9.38, the browser parameter will be parsed into arguments 275 * separated by spaces or tabs. 276 * %1, if present, will be replaced with the url. 277 * Arguments may be surrounded by single or double quotes if 278 * they contain spaces or tabs. 279 * There is no mechanism to escape quotes or other chars with backslashes. 280 * 281 * BLOCKING. However, this does NOT probe the server port to see if it is ready. 245 282 * 246 283 * @param url The URL to open. 247 * @param browser The browser to use. 284 * @param browser The browser to use. See above for quoting rules. 248 285 * @return <code>true</code> if the operation was successful, 249 286 * otherwise <code>false</code>. … … 254 291 waitForServer(url); 255 292 if (validateUrlFormat(url)) { 256 if (_shellCommand.executeSilentAndWaitTimed(browser + " " + url, 5)) 257 return true; 293 String[] args = parseArgs(browser, url); 294 if (args.length > 0) { 295 if (_log.shouldDebug()) _log.debug("Execute: " + Arrays.toString(args)); 296 if (_shellCommand.executeSilentAndWaitTimed(args, 5)) 297 return true; 298 } 258 299 } 259 300 return false; 301 } 302 303 /** 304 * Parse args into arguments 305 * separated by spaces or tabs. 306 * %1, if present, will be replaced with the url, 307 * otherwise it will be added as the last argument. 308 * Arguments may be surrounded by single or double quotes if 309 * they contain spaces or tabs. 310 * There is no mechanism to escape quotes or other chars with backslashes. 311 * Adapted from i2ptunnel SSLHelper. 312 * 313 * @return param args non-null 314 * @return non-null 315 * @since 0.9.38 316 */ 317 private static String[] parseArgs(String args, String url) { 318 List<String> argList = new ArrayList<String>(4); 319 StringBuilder buf = new StringBuilder(32); 320 boolean isQuoted = false; 321 for (int j = 0; j < args.length(); j++) { 322 char c = args.charAt(j); 323 switch (c) { 324 case '\'': 325 case '"': 326 if (isQuoted) { 327 String str = buf.toString().trim(); 328 if (str.length() > 0) 329 argList.add(str); 330 buf.setLength(0); 331 } 332 isQuoted = !isQuoted; 333 break; 334 case ' ': 335 case '\t': 336 // whitespace - if we're in a quoted section, keep this as part of the quote, 337 // otherwise use it as a delim 338 if (isQuoted) { 339 buf.append(c); 340 } else { 341 String str = buf.toString().trim(); 342 if (str.length() > 0) 343 argList.add(str); 344 buf.setLength(0); 345 } 346 break; 347 default: 348 buf.append(c); 349 break; 350 } 351 } 352 if (buf.length() > 0) { 353 String str = buf.toString().trim(); 354 if (str.length() > 0) 355 argList.add(str); 356 } 357 if (argList.isEmpty()) 358 return new String[] {}; 359 boolean foundpct = false; 360 // replace %1 with the url 361 for (int i = 0; i < argList.size(); i++) { 362 String arg = argList.get(i); 363 if (arg.contains("%1")) { 364 argList.set(i, arg.replace("%1", url)); 365 foundpct = true; 366 } 367 } 368 // add url if no %1 369 if (!foundpct) 370 argList.add(url); 371 return argList.toArray(new String[argList.size()]); 260 372 } 261 373 -
core/java/src/net/i2p/util/ShellCommand.java
r51bf23a r9738db7 18 18 import java.io.OutputStreamWriter; 19 19 import java.util.Arrays; 20 21 import net.i2p.I2PAppContext; 20 22 21 23 /** … … 29 31 public class ShellCommand { 30 32 31 private static final boolean DEBUG = false;32 33 private static final boolean CONSUME_OUTPUT = true; 33 34 private static final boolean NO_CONSUME_OUTPUT = false; … … 359 360 String name = null; 360 361 long begin = 0; 361 if (DEBUG) { 362 Log log = I2PAppContext.getGlobalContext().logManager().getLog(ShellCommand.class); 363 if (log.shouldDebug()) { 362 364 if (shellCommand instanceof String) { 363 365 name = (String) shellCommand; … … 375 377 commandThread.join(seconds * 1000); 376 378 if (commandThread.isAlive()) { 377 if ( DEBUG)378 System.out.println("ShellCommand gave up waiting for \"" + name + "\" after " + seconds + " seconds");379 if (log.shouldDebug()) 380 log.debug("ShellCommand gave up waiting for \"" + name + "\" after " + seconds + " seconds"); 379 381 return true; 380 382 } … … 383 385 // Wake up, time to die. 384 386 } 385 if ( DEBUG)386 System.out.println("ShellCommand returning " + result.commandSuccessful + " for \"" + name + "\" after " + (System.currentTimeMillis() - begin) + " ms");387 if (log.shouldDebug()) 388 log.debug("ShellCommand returning " + result.commandSuccessful + " for \"" + name + "\" after " + (System.currentTimeMillis() - begin) + " ms"); 387 389 return result.commandSuccessful; 388 390 } … … 427 429 Process process; 428 430 String name = null; // for debugging only 431 Log log = I2PAppContext.getGlobalContext().logManager().getLog(ShellCommand.class); 429 432 try { 430 433 // easy way so we don't have to copy this whole method 431 434 if (shellCommand instanceof String) { 432 435 name = (String) shellCommand; 433 if ( DEBUG)434 System.out.println("ShellCommand exec \"" + name + "\" consume? " + consumeOutput + " wait? " + waitForExitStatus);436 if (log.shouldDebug()) 437 log.debug("ShellCommand exec \"" + name + "\" consume? " + consumeOutput + " wait? " + waitForExitStatus); 435 438 process = Runtime.getRuntime().exec(name); 436 439 } else if (shellCommand instanceof String[]) { 437 440 String[] arr = (String[]) shellCommand; 438 if ( DEBUG) {441 if (log.shouldDebug()) { 439 442 name = Arrays.toString(arr); 440 System.out.println("ShellCommand exec \"" + name + "\" consume? " + consumeOutput + " wait? " + waitForExitStatus);443 log.debug("ShellCommand exec \"" + name + "\" consume? " + consumeOutput + " wait? " + waitForExitStatus); 441 444 } 442 445 process = Runtime.getRuntime().exec(arr); … … 462 465 } 463 466 if (waitForExitStatus) { 464 if ( DEBUG)465 System.out.println("ShellCommand waiting for \"" + name + '\"');467 if (log.shouldDebug()) 468 log.debug("ShellCommand waiting for \"" + name + '\"'); 466 469 try { 467 470 process.waitFor(); 468 471 } catch (InterruptedException e) { 469 if (DEBUG) { 470 System.out.println("ShellCommand exception waiting for \"" + name + '\"'); 471 e.printStackTrace(); 472 if (log.shouldWarn()) { 473 log.warn("ShellCommand exception waiting for \"" + name + '"', e); 472 474 } 473 475 if (!consumeOutput) … … 479 481 killStreams(); 480 482 481 if ( DEBUG)482 System.out.println("ShellCommand exit value is " + process.exitValue() + " for \"" + name + '\"');483 if (log.shouldDebug()) 484 log.debug("ShellCommand exit value is " + process.exitValue() + " for \"" + name + '\"'); 483 485 if (process.exitValue() > 0) 484 486 return false; … … 486 488 } catch (IOException e) { 487 489 // probably IOException, file not found from exec() 488 if (DEBUG) { 489 System.out.println("ShellCommand execute exception for \"" + name + '\"'); 490 e.printStackTrace(); 490 if (log.shouldWarn()) { 491 log.warn("ShellCommand execute exception for \"" + name + '"', e); 491 492 } 492 493 return false; -
history.txt
r51bf23a r9738db7 1 2018-12-12 zzz 2 * DTG: Use UrlLauncher to launch browser 3 * Installer: Drop unused systray.config 4 * UrlLauncher: Improvements and cleanups 5 * Util: Add another ShellCommand String[] method 6 7 2018-12-11 zzz 8 * Crypto: HMAC-SHA256 cleanup 9 * Debian: Add conffiles list 10 * Utils: Enable TLSv1.3 for SSL sockets 11 12 2018-12-08 zzz 13 * Console: Hide I2CP config if disabled 14 * NetDb: Allow longer expiration for Meta LS2 15 * Transport: 16 - Don't repeatedly publish RI if IPv6-only but 17 not configured IPv6-only 18 - Don't set status to disconnected if IPv6-only but 19 not configured IPv6-only 20 21 2018-12-05 zzz 22 * I2CP: 23 - Propagate error from disconnect message to session listener 24 - Set offline keys in generated LS2 25 - Set and validate offline sig in SessionConfig 26 1 27 2018-12-04 zzz 2 28 * Data: Add preliminary PrivateKeyFile support for LS2 offline keys (proposal #123) -
router/java/src/net/i2p/router/RouterVersion.java
r51bf23a r9738db7 19 19 public final static String ID = "Monotone"; 20 20 public final static String VERSION = CoreVersion.VERSION; 21 public final static long BUILD = 8;21 public final static long BUILD = 9; 22 22 23 23 /** for example "-test" */
Note: See TracChangeset
for help on using the changeset viewer.