/** * Modified from LoadClientAppsJob and I2PTunnelHTTPClientBase * All keys are mapped to lower case. * * @param args non-null * @since 0.9.4 */ private static Map<String, String> parseArgs(String args) { Map<String, String> rv = new HashMap<String, String>(8); char data[] = args.toCharArray(); StringBuilder buf = new StringBuilder(32); boolean isQuoted = false; String key = null; for (int i = 0; i < data.length; i++) { switch (data[i]) { case '\'': case '"': if (isQuoted) { // keys never quoted if (key != null) { rv.put(key, buf.toString().trim()); key = null; } buf.setLength(0); } isQuoted = !isQuoted; break; case ' ': case '\r': case '\n': case '\t': case ',': // whitespace - if we're in a quoted section, keep this as part of the quote, // otherwise use it as a delim if (isQuoted) { buf.append(data[i]); } else { if (key != null) { rv.put(key, buf.toString().trim()); key = null; } buf.setLength(0); } break; case '=': if (isQuoted) { buf.append(data[i]); } else { key = buf.toString().trim().toLowerCase(Locale.US); buf.setLength(0); } break; default: buf.append(data[i]); break; } } if (key != null) rv.put(key, buf.toString().trim()); return rv; }
/** * Parse the installed (not the temp) news file for the latest version. * TODO: Real XML parsing * TODO: Check minVersion, use backup URLs specified */ void checkForUpdates() { FileInputStream in = null; try { in = new FileInputStream(_newsFile); StringBuilder buf = new StringBuilder(128); while (DataHelper.readLine(in, buf)) { int index = buf.indexOf(VERSION_PREFIX); if (index >= 0) { Map<String, String> args = parseArgs(buf.substring(index+VERSION_PREFIX.length())); String ver = args.get(VERSION_KEY); if (ver != null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Found version: [" + ver + "]"); if (TrustedUpdate.needsUpdate(RouterVersion.VERSION, ver)) { if (NewsHelper.isUpdateDisabled(_context)) { String msg = _mgr._("In-network updates disabled. Check package manager."); _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg); _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); return; } if (NewsHelper.isBaseReadonly(_context)) { String msg = _mgr._("No write permission for I2P install directory."); _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg); _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); return; } String minRouter = args.get(MIN_VERSION_KEY); if (minRouter != null) { if (VersionComparator.comp(RouterVersion.VERSION, minRouter) < 0) { String msg = _mgr._("You must first update to version {0}", minRouter); _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg); _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); return; } } String minJava = args.get(MIN_JAVA_VERSION_KEY); if (minJava != null) { String ourJava = System.getProperty("java.version"); if (VersionComparator.comp(ourJava, minJava) < 0) { String msg = _mgr._("Requires Java version {0} but installed Java version is {1}", minJava, ourJava); _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg); _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); return; } } if (_log.shouldLog(Log.DEBUG)) _log.debug("Our version is out of date, update!"); // TODO if minversion > our version, continue // and look for a second entry with clearnet URLs // TODO clearnet URLs, notify with HTTP_CLEARNET and/or HTTPS_CLEARNET Map<UpdateMethod, List<URI>> sourceMap = new HashMap<UpdateMethod, List<URI>>(4); // Must do su3 first if (ConfigUpdateHandler.USE_SU3_UPDATE) { sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED_SU3, "", HTTP)); addMethod(TORRENT, args.get(SU3_KEY), sourceMap); addMethod(HTTP_CLEARNET, args.get(CLEARNET_HTTP_SU3_KEY), sourceMap); addMethod(HTTPS_CLEARNET, args.get(CLEARNET_HTTPS_SU3_KEY), sourceMap); // notify about all sources at once _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED_SU3, "", sourceMap, ver, ""); sourceMap.clear(); } // now do sud/su2 sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP)); String key = FileUtil.isPack200Supported() ? SU2_KEY : SUD_KEY; addMethod(TORRENT, args.get(key), sourceMap); // notify about all sources at once _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED, "", sourceMap, ver, ""); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Our version is current"); } return; } else { if (_log.shouldLog(Log.WARN)) _log.warn("No version in " + buf.toString()); } } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("No match in " + buf.toString()); } buf.setLength(0); } } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) _log.warn("Error checking the news for an update", ioe); return; } finally { if (in != null) try { in.close(); } catch (IOException ioe) {} } if (_log.shouldLog(Log.WARN)) _log.warn("No version found in news.xml file"); }